Skip to content

Commit

Permalink
Fix Endpoints for File/id, File Search, ReleaseManagement Series, and…
Browse files Browse the repository at this point in the history
… Add Filter Name and Group
  • Loading branch information
da3dsoul committed Dec 29, 2023
1 parent 8a83127 commit 4f5bbca
Show file tree
Hide file tree
Showing 61 changed files with 157 additions and 30 deletions.
27 changes: 11 additions & 16 deletions Shoko.Server/API/v3/Controllers/FileController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,16 +103,12 @@ public ActionResult<ListResult<File>> Search([FromRoute] string query,
[FromQuery, ModelBinder(typeof(CommaDelimitedModelBinder))] HashSet<DataSource> includeDataFrom = null,
[FromQuery] bool fuzzy = true)
{
var enumerable = ModelHelper.FilterFiles(RepoFactory.VideoLocal.GetAll(), User, pageSize, page, include, exclude, include_only, sortOrder,
includeDataFrom).List;

// Search.
var searched = enumerable
.Search(query, tuple => tuple.Locations.Select(place => place.AbsolutePath).Where(path => path != null), fuzzy)
.Select(result => result.Result);

// Skip and limit.
return searched.ToListResult(page, pageSize);
var searched = RepoFactory.VideoLocal.GetAll()
.Search(query, tuple => tuple.Places.Select(place => place?.FilePath).Where(path => path != null), fuzzy)
.Select(result => result.Result).Skip((page-1)*pageSize).Take(pageSize).ToList();
return ModelHelper.FilterFiles(searched, User, pageSize, page, include, exclude, include_only, sortOrder,
includeDataFrom);
}

/// <summary>
Expand Down Expand Up @@ -161,21 +157,20 @@ public ActionResult DeleteFiles([FromBody] File.Input.BatchDeleteBody body = nul
/// Get File Details
/// </summary>
/// <param name="fileID">Shoko VideoLocalID</param>
/// <param name="includeXRefs">Set to true to include series and episode cross-references.</param>
/// <param name="include">Include items that are not included by default</param>
/// <param name="includeDataFrom">Include data from selected <see cref="DataSource"/>s.</param>
/// <param name="includeMediaInfo">Include media info data.</param>
/// <param name="includeAbsolutePaths">Include absolute paths for the file locations.</param>
/// <returns></returns>
[HttpGet("{fileID}")]
public ActionResult<File> GetFile([FromRoute] int fileID, [FromQuery] bool includeXRefs = false,
[FromQuery, ModelBinder(typeof(CommaDelimitedModelBinder))] HashSet<DataSource> includeDataFrom = null,
[FromQuery] bool includeMediaInfo = false, [FromQuery] bool includeAbsolutePaths = false)
public ActionResult<File> GetFile([FromRoute] int fileID, [FromQuery, ModelBinder(typeof(CommaDelimitedModelBinder))] FileNonDefaultIncludeType[] include = default,
[FromQuery, ModelBinder(typeof(CommaDelimitedModelBinder))] HashSet<DataSource> includeDataFrom = null)
{
var file = RepoFactory.VideoLocal.GetByID(fileID);
if (file == null)
return NotFound(FileNotFoundWithFileID);

return new File(HttpContext, file, includeXRefs, includeDataFrom, includeMediaInfo, includeAbsolutePaths);
include ??= Array.Empty<FileNonDefaultIncludeType>();
return new File(HttpContext, file, include.Contains(FileNonDefaultIncludeType.XRefs), includeDataFrom,
include.Contains(FileNonDefaultIncludeType.MediaInfo), include.Contains(FileNonDefaultIncludeType.AbsolutePaths));
}

/// <summary>
Expand Down
9 changes: 7 additions & 2 deletions Shoko.Server/API/v3/Controllers/FilterController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Shoko.Server.API.v3.Helpers;
using Shoko.Server.API.v3.Models.Common;
using Shoko.Server.API.v3.Models.Shoko;
using Shoko.Server.Extensions;
using Shoko.Server.Filters;
using Shoko.Server.Filters.Interfaces;
using Shoko.Server.Models;
Expand Down Expand Up @@ -150,7 +151,9 @@ public ActionResult<Filter> AddNewFilter(Filter.Input.CreateOrUpdateFilterBody b
};
return new Filter.FilterExpressionHelp
{
Expression = a.Name.Replace("Expression", "").Replace("Function", ""),
Expression = a.Name.TrimEnd("Expression").TrimEnd("Function").TrimEnd("Selector").Trim(),
Name = expression.Name,
Group = expression.Group,
Description = expression.HelpDescription,
PossibleParameters = expression.HelpPossibleParameters,
PossibleSecondParameters = expression.HelpPossibleSecondParameters,
Expand Down Expand Up @@ -186,7 +189,9 @@ public ActionResult<Filter> AddNewFilter(Filter.Input.CreateOrUpdateFilterBody b
if (criteria == null) return null;
return new Filter.SortingCriteriaHelp
{
Type = a.Name.Replace("SortingSelector", ""), Description = criteria.HelpDescription
Type = a.Name.TrimEnd("SortingSelector").Trim(),
Name = criteria.Name,
Description = criteria.HelpDescription
};
}).Where(a => a != null).ToArray();
return _sortingTypes;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public ActionResult<ListResult<SeriesWithMultipleReleasesResult>> GetSeriesWithM
/// <returns></returns>
[HttpGet("Series/{seriesID}")]
public ActionResult<ListResult<Episode>> GetEpisodesForSeries(
int seriesID,
[FromRoute] int seriesID,
[FromQuery, ModelBinder(typeof(CommaDelimitedModelBinder))] HashSet<DataSource> includeDataFrom = null,
[FromQuery] bool includeFiles = true,
[FromQuery] bool includeMediaInfo = true,
Expand All @@ -79,7 +79,7 @@ public ActionResult<ListResult<Episode>> GetEpisodesForSeries(
if (!User.AllowedSeries(series))
return new ListResult<Episode>();

IEnumerable<SVR_AnimeEpisode> enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations);
IEnumerable<SVR_AnimeEpisode> enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations, series.AniDB_ID);

return enumerable
.ToListResult(episode => new Episode(HttpContext, episode, includeDataFrom, includeFiles, includeMediaInfo, includeAbsolutePaths), page, pageSize);
Expand Down Expand Up @@ -121,7 +121,7 @@ public ActionResult<ListResult<Episode>> GetEpisodes(
/// <returns></returns>
[HttpGet("Series/{seriesID}/Episode/FilesToDelete")]
public ActionResult<List<int>> GetFileIdsWithPreference(
int seriesID,
[FromRoute] int seriesID,
[FromQuery] bool ignoreVariations = true
)
{
Expand All @@ -132,7 +132,7 @@ public ActionResult<List<int>> GetFileIdsWithPreference(
if (!User.AllowedSeries(series))
return new List<int>();

IEnumerable<SVR_AnimeEpisode> enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations);
IEnumerable<SVR_AnimeEpisode> enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations, series.AniDB_ID);

return enumerable
.SelectMany(episode =>
Expand Down
13 changes: 7 additions & 6 deletions Shoko.Server/API/v3/Helpers/FilterFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Shoko.Commons.Extensions;
using Shoko.Models.Enums;
using Shoko.Server.API.v3.Models.Shoko;
using Shoko.Server.Extensions;
using Shoko.Server.Filters;
using Shoko.Server.Filters.Interfaces;
using Shoko.Server.Models;
Expand All @@ -28,11 +29,11 @@ public FilterFactory(IHttpContextAccessor context, FilterEvaluator evaluator)

_expressionTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes())
.Where(a => a != typeof(FilterExpression) && !a.IsGenericType && typeof(FilterExpression).IsAssignableFrom(a) &&
!typeof(SortingExpression).IsAssignableFrom(a)).ToDictionary(a => a.Name.Replace("Expression", "").Replace("Function", "").Replace("Selector", ""));
!typeof(SortingExpression).IsAssignableFrom(a)).ToDictionary(a => a.Name.TrimEnd("Expression").TrimEnd("Function").TrimEnd("Selector"));

_sortingTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes())
.Where(a => a != typeof(FilterExpression) && !a.IsAbstract && !a.IsGenericType && typeof(SortingExpression).IsAssignableFrom(a))
.ToDictionary(a => a.Name.Replace("SortingSelector", ""));
.ToDictionary(a => a.Name.TrimEnd("SortingSelector"));
}

public Filter GetFilter(FilterPreset groupFilter, bool fullModel = false)
Expand Down Expand Up @@ -101,7 +102,7 @@ public Filter.FilterCondition GetExpressionTree(FilterExpression expression)
if (expression is null) return null;
var result = new Filter.FilterCondition
{
Type = expression.GetType().Name.Replace("Expression", "").Replace("Function", "").Replace("Selector", "")
Type = expression.GetType().Name.TrimEnd("Expression").TrimEnd("Function").TrimEnd("Selector").Trim()
};

// Left/First
Expand Down Expand Up @@ -164,7 +165,7 @@ public Filter.FilterCondition GetExpressionTree(FilterExpression expression)
public FilterExpression<T> GetExpressionTree<T>(Filter.FilterCondition condition)
{
if (condition is null) return null;
if (!_expressionTypes.TryGetValue(condition.Type.Replace("Expression", "").Replace("Function", "").Replace("Selector", ""), out var type))
if (!_expressionTypes.TryGetValue(condition.Type.TrimEnd("Expression").TrimEnd("Function").TrimEnd("Selector").Trim(), out var type))
throw new ArgumentException($"FilterCondition type {condition.Type} was not found");
var result = (FilterExpression<T>)Activator.CreateInstance(type);

Expand Down Expand Up @@ -235,7 +236,7 @@ public Filter.SortingCriteria GetSortingCriteria(SortingExpression expression)

var result = new Filter.SortingCriteria
{
Type = expression.GetType().Name.Replace("SortingSelector", ""),
Type = expression.GetType().Name.TrimEnd("SortingSelector"),
IsInverted = expression.Descending
};

Expand All @@ -245,7 +246,7 @@ public Filter.SortingCriteria GetSortingCriteria(SortingExpression expression)
{
currentCriteria.Next = new Filter.SortingCriteria
{
Type = currentExpression.GetType().Name.Replace("SortingSelector", ""),
Type = currentExpression.GetType().Name.TrimEnd("SortingSelector"),
IsInverted = currentExpression.Descending
};
currentCriteria = currentCriteria.Next;
Expand Down
19 changes: 19 additions & 0 deletions Shoko.Server/API/v3/Models/Shoko/Filter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Shoko.Server.API.v3.Models.Common;
using Shoko.Server.Filters;

// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
Expand Down Expand Up @@ -116,6 +117,18 @@ public class FilterExpressionHelp
/// </summary>
[Required]
public string Expression { get; init; }

/// <summary>
/// The human readable name of the Expression
/// </summary>
[Required]
public string Name { get; init; }

/// <summary>
/// The group that this filter expression belongs to. This can help with filtering the expression types
/// </summary>
[Required]
public FilterExpressionGroup Group { get; init; }

/// <summary>
/// A description of what the expression is doing, comparing, etc
Expand Down Expand Up @@ -214,6 +227,12 @@ public class SortingCriteriaHelp
[Required]
public string Type { get; init; }

/// <summary>
/// Human readable name
/// </summary>
[Required]
public string Name { get; set; }

/// <summary>
/// A description of what the expression is doing, comparing, etc
/// </summary>
Expand Down
39 changes: 39 additions & 0 deletions Shoko.Server/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,43 @@ public static bool EqualsInvariantIgnoreCase(this string value1, string value2)
{
return value1.Equals(value2, StringComparison.InvariantCultureIgnoreCase);
}

public static string CamelCaseToNatural(this string text, bool preserveAcronyms=true)
{
if (string.IsNullOrWhiteSpace(text))
return string.Empty;
StringBuilder newText = new StringBuilder(text.Length * 2);
newText.Append(text[0]);
for (int i = 1; i < text.Length; i++)
{
if (char.IsUpper(text[i]))
if ((text[i - 1] != ' ' && !char.IsUpper(text[i - 1])) ||
(preserveAcronyms && char.IsUpper(text[i - 1]) &&
i < text.Length - 1 && !char.IsUpper(text[i + 1])))
newText.Append(' ');
newText.Append(text[i]);
}
return newText.ToString();
}

public static string TrimStart(this string inputText, string value, StringComparison comparisonType = StringComparison.CurrentCultureIgnoreCase)
{
if (string.IsNullOrEmpty(value)) return inputText;
while (!string.IsNullOrEmpty(inputText) && inputText.StartsWith(value, comparisonType)) inputText = inputText[(value.Length - 1)..];

return inputText;
}

public static string TrimEnd(this string inputText, string value, StringComparison comparisonType = StringComparison.CurrentCultureIgnoreCase)
{
if (string.IsNullOrEmpty(value)) return inputText;
while (!string.IsNullOrEmpty(inputText) && inputText.EndsWith(value, comparisonType)) inputText = inputText[..^value.Length];

return inputText;
}

public static string Trim(this string inputText, string value, StringComparison comparisonType = StringComparison.CurrentCultureIgnoreCase)
{
return TrimStart(TrimEnd(inputText, value, comparisonType), value, comparisonType);
}
}
4 changes: 4 additions & 0 deletions Shoko.Server/Filters/FilterExpression.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Shoko.Server.Extensions;
using Shoko.Server.Filters.Interfaces;

namespace Shoko.Server.Filters;
Expand All @@ -9,6 +10,9 @@ public class FilterExpression : IFilterExpression
{
[IgnoreDataMember] [JsonIgnore] public virtual bool TimeDependent => false;
[IgnoreDataMember] [JsonIgnore] public virtual bool UserDependent => false;
[IgnoreDataMember] [JsonIgnore] public virtual string Name =>
GetType().Name.TrimEnd("Expression").TrimEnd("Function").TrimEnd("SortingSelector").TrimEnd("Selector").CamelCaseToNatural();
[IgnoreDataMember] [JsonIgnore] public virtual FilterExpressionGroup Group => FilterExpressionGroup.Info;
[IgnoreDataMember] [JsonIgnore] public virtual string HelpDescription => string.Empty;
[IgnoreDataMember] [JsonIgnore] public virtual string[] HelpPossibleParameters => Array.Empty<string>();
[IgnoreDataMember] [JsonIgnore] public virtual string[] HelpPossibleSecondParameters => Array.Empty<string>();
Expand Down
12 changes: 12 additions & 0 deletions Shoko.Server/Filters/FilterExpressionGroup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace Shoko.Server.Filters;

[JsonConverter(typeof(StringEnumConverter))]
public enum FilterExpressionGroup
{
Info,
Logic,
Function,
Selector
}
1 change: 1 addition & 0 deletions Shoko.Server/Filters/Functions/DateAddFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public DateAddFunction(FilterExpression<DateTime?> selector, TimeSpan parameter)
public override bool TimeDependent => Selector.TimeDependent;
public override bool UserDependent => Selector.UserDependent;
public override string HelpDescription => "This adds a timespan to a date selector";
public override FilterExpressionGroup Group => FilterExpressionGroup.Function;

public FilterExpression<DateTime?> Left
{
Expand Down
1 change: 1 addition & 0 deletions Shoko.Server/Filters/Functions/DateDiffFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public DateDiffFunction() { }
public override bool TimeDependent => Selector.TimeDependent;
public override bool UserDependent => Selector.UserDependent;
public override string HelpDescription => "This subtracts a timespan from a date selector.";
public override FilterExpressionGroup Group => FilterExpressionGroup.Function;

public FilterExpression<DateTime?> Left
{
Expand Down
1 change: 1 addition & 0 deletions Shoko.Server/Filters/Functions/TodayFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public class TodayFunction : FilterExpression<DateTime?>
public override bool TimeDependent => true;
public override bool UserDependent => false;
public override string HelpDescription => "This returns the current date, at midnight (00:00:00.0000)";
public override FilterExpressionGroup Group => FilterExpressionGroup.Function;

public override DateTime? Evaluate(IFilterable filterable, IFilterableUserInfo userInfo)
{
Expand Down
1 change: 1 addition & 0 deletions Shoko.Server/Filters/Info/HasTMDbLinkExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public class HasTMDbLinkExpression : FilterExpression<bool>
{
public override bool TimeDependent => false;
public override bool UserDependent => false;
public override string Name => "Has TMDb Link";
public override string HelpDescription => "This passes if any of the anime have a TMDb link";

public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo)
Expand Down
1 change: 1 addition & 0 deletions Shoko.Server/Filters/Info/HasTvDBLinkExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public class HasTvDBLinkExpression : FilterExpression<bool>
{
public override bool TimeDependent => false;
public override bool UserDependent => false;
public override string Name => "Has TvDB Link";
public override string HelpDescription => "This passes if any of the anime have a TvDB link";

public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo)
Expand Down
1 change: 1 addition & 0 deletions Shoko.Server/Filters/Info/MissingTMDbLinkExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class MissingTMDbLinkExpression : FilterExpression<bool>
{
public override bool TimeDependent => false;
public override bool UserDependent => false;
public override string Name => "Missing TMDb Link";
public override string HelpDescription => "This passes if any of the anime should have a TMDb link but does not have one";

public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo)
Expand Down
1 change: 1 addition & 0 deletions Shoko.Server/Filters/Info/MissingTvDBLinkExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class MissingTvDBLinkExpression : FilterExpression<bool>
{
public override bool TimeDependent => false;
public override bool UserDependent => false;
public override string Name => "Missing TvDB Link";
public override string HelpDescription => "This passes if any of the anime should have a TvDB link but does not have one";

public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public DateEqualsExpression() { }
public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false);
public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false);
public override string HelpDescription => "This passes if the left selector equals either the right selector or the parameter";
public override FilterExpressionGroup Group => FilterExpressionGroup.Logic;

public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public DateGreaterThanEqualsExpression() { }
public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false);
public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false);
public override string HelpDescription => "This passes if the left selector is greater than or equal to either the right selector or the parameter";
public override FilterExpressionGroup Group => FilterExpressionGroup.Logic;

public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public DateGreaterThanExpression() { }
public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false);
public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false);
public override string HelpDescription => "This passes if the left selector is greater than either the right selector or the parameter";
public override FilterExpressionGroup Group => FilterExpressionGroup.Logic;

public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public DateLessThanEqualsExpression() { }
public override bool TimeDependent => Left.TimeDependent || (Right?.TimeDependent ?? false);
public override bool UserDependent => Left.UserDependent || (Right?.UserDependent ?? false);
public override string HelpDescription => "This passes if the left selector is less than or equal to either the right selector or the parameter";
public override FilterExpressionGroup Group => FilterExpressionGroup.Logic;

public override bool Evaluate(IFilterable filterable, IFilterableUserInfo userInfo)
{
Expand Down
Loading

0 comments on commit 4f5bbca

Please sign in to comment.