mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
Migration Changes (#2392)
This commit is contained in:
parent
f8ab6a1f2b
commit
6cf100b1d4
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using API.Data.ManualMigrations;
|
||||||
using API.DTOs.Filtering;
|
using API.DTOs.Filtering;
|
||||||
using API.DTOs.Filtering.v2;
|
using API.DTOs.Filtering.v2;
|
||||||
using API.Entities.Enums;
|
using API.Entities.Enums;
|
||||||
@ -102,6 +103,24 @@ public class SmartFilterHelperTests
|
|||||||
Assert.False(decoded.SortOptions.IsAscending);
|
Assert.False(decoded.SortOptions.IsAscending);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("name=DC%20-%20On%20Deck&stmts=comparison%3D1%26field%3D20%26value%3D0,comparison%3D9%26field%3D20%26value%3D100,comparison%3D0%26field%3D19%26value%3D274&sortOptions=sortField%3D1&isAscending=True&limitTo=0&combination=1")]
|
||||||
|
[InlineData("name=Manga%20-%20On%20Deck&stmts=comparison%253D1%252Cfield%253D20%252Cvalue%253D0,comparison%253D3%252Cfield%253D20%252Cvalue%253D100,comparison%253D0%252Cfield%253D19%252Cvalue%253D2&sortOptions=sortField%3D1,isAscending%3DTrue&limitTo=0&combination=1")]
|
||||||
|
[InlineData("name=English%20In%20Progress&stmts=comparison%253D8%252Cfield%253D7%252Cvalue%253D4%25252C3,comparison%253D3%252Cfield%253D20%252Cvalue%253D100,comparison%253D8%252Cfield%253D3%252Cvalue%253Dja,comparison%253D1%252Cfield%253D20%252Cvalue%253D0&sortOptions=sortField%3D7,isAscending%3DFalse&limitTo=0&combination=1")]
|
||||||
|
public void MigrationWorks(string filter)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var updatedFilter = MigrateSmartFilterEncoding.EncodeFix(filter);
|
||||||
|
Assert.NotNull(updatedFilter);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Assert.Fail("Exception thrown: " + ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private static void AssertStatementSame(FilterStatementDto statement, FilterStatementDto statement2)
|
private static void AssertStatementSame(FilterStatementDto statement, FilterStatementDto statement2)
|
||||||
{
|
{
|
||||||
Assert.Equal(statement.Field, statement2.Field);
|
Assert.Equal(statement.Field, statement2.Field);
|
||||||
|
@ -13,42 +13,24 @@ namespace API.Data.ManualMigrations;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class MigrateSmartFilterEncoding
|
public static class MigrateSmartFilterEncoding
|
||||||
{
|
{
|
||||||
|
private static readonly Regex StatementsRegex = new Regex("stmts=(?<Statements>.*?)&");
|
||||||
|
private const string ValueRegex = @"value=(?<value>\d+)";
|
||||||
|
private const string FieldRegex = @"field=(?<value>\d+)";
|
||||||
|
private const string ComparisonRegex = @"comparison=(?<value>\d+)";
|
||||||
|
private const string SortOptionsRegex = @"sortField=(.*?),isAscending=(.*?)";
|
||||||
|
|
||||||
public static async Task Migrate(IUnitOfWork unitOfWork, DataContext dataContext, ILogger<Program> logger)
|
public static async Task Migrate(IUnitOfWork unitOfWork, DataContext dataContext, ILogger<Program> logger)
|
||||||
{
|
{
|
||||||
logger.LogCritical("Running MigrateSmartFilterEncoding migration - Please be patient, this may take some time. This is not an error");
|
logger.LogCritical("Running MigrateSmartFilterEncoding migration - Please be patient, this may take some time. This is not an error");
|
||||||
|
|
||||||
var statementsRegex = new Regex("stmts=(?<Statements>.*?)&");
|
|
||||||
const string valueRegex = @"value=(?<value>\d+)";
|
|
||||||
const string fieldRegex = @"field=(?<value>\d+)";
|
|
||||||
const string comparisonRegex = @"comparison=(?<value>\d+)";
|
|
||||||
var smartFilters = dataContext.AppUserSmartFilter.ToList();
|
var smartFilters = dataContext.AppUserSmartFilter.ToList();
|
||||||
foreach (var filter in smartFilters)
|
foreach (var filter in smartFilters)
|
||||||
{
|
{
|
||||||
if (filter.Filter.Contains(SmartFilterHelper.StatementSeparator)) continue;
|
if (filter.Filter.Contains(SmartFilterHelper.StatementSeparator)) continue;
|
||||||
var statements = statementsRegex.Matches(filter.Filter)
|
var decode = EncodeFix(filter.Filter);
|
||||||
.Select(match => match.Groups["Statements"])
|
if (string.IsNullOrEmpty(decode)) continue;
|
||||||
.FirstOrDefault(group => group.Success && group != Match.Empty)?.Value;
|
filter.Filter = decode;
|
||||||
if (string.IsNullOrEmpty(statements)) continue;
|
|
||||||
|
|
||||||
|
|
||||||
// We have statements. Let's remove the statements and generate a filter dto
|
|
||||||
var noStmt = statementsRegex.Replace(filter.Filter, string.Empty).Replace("stmts=", string.Empty);
|
|
||||||
var filterDto = SmartFilterHelper.Decode(noStmt);
|
|
||||||
|
|
||||||
// Now we just parse each individual stmt into the core components and add to statements
|
|
||||||
|
|
||||||
var individualParts = Uri.UnescapeDataString(statements).Split(',').Select(Uri.UnescapeDataString);
|
|
||||||
foreach (var part in individualParts)
|
|
||||||
{
|
|
||||||
filterDto.Statements.Add(new FilterStatementDto()
|
|
||||||
{
|
|
||||||
Value = Regex.Match(part, valueRegex).Groups["value"].Value,
|
|
||||||
Field = Enum.Parse<FilterField>(Regex.Match(part, fieldRegex).Groups["value"].Value),
|
|
||||||
Comparison = Enum.Parse<FilterComparison>(Regex.Match(part, comparisonRegex).Groups["value"].Value),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
filter.Filter = SmartFilterHelper.Encode(filterDto);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unitOfWork.HasChanges())
|
if (unitOfWork.HasChanges())
|
||||||
@ -58,4 +40,47 @@ public static class MigrateSmartFilterEncoding
|
|||||||
|
|
||||||
logger.LogCritical("Running MigrateSmartFilterEncoding migration - Completed. This is not an error");
|
logger.LogCritical("Running MigrateSmartFilterEncoding migration - Completed. This is not an error");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string EncodeFix(string encodedFilter)
|
||||||
|
{
|
||||||
|
var statements = StatementsRegex.Matches(encodedFilter)
|
||||||
|
.Select(match => match.Groups["Statements"])
|
||||||
|
.FirstOrDefault(group => group.Success && group != Match.Empty)?.Value;
|
||||||
|
if (string.IsNullOrEmpty(statements)) return encodedFilter;
|
||||||
|
|
||||||
|
|
||||||
|
// We have statements. Let's remove the statements and generate a filter dto
|
||||||
|
var noStmt = StatementsRegex.Replace(encodedFilter, string.Empty).Replace("stmts=", string.Empty);
|
||||||
|
|
||||||
|
// Pre-v0.7.10 filters could be extra escaped
|
||||||
|
if (!noStmt.Contains("sortField="))
|
||||||
|
{
|
||||||
|
noStmt = Uri.UnescapeDataString(noStmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to replace sort options portion with a properly encoded
|
||||||
|
noStmt = Regex.Replace(noStmt, SortOptionsRegex, match =>
|
||||||
|
{
|
||||||
|
var sortFieldValue = match.Groups[1].Value;
|
||||||
|
var isAscendingValue = match.Groups[2].Value;
|
||||||
|
|
||||||
|
return $"sortField={sortFieldValue}{SmartFilterHelper.InnerStatementSeparator}isAscending={isAscendingValue}";
|
||||||
|
});
|
||||||
|
|
||||||
|
var filterDto = SmartFilterHelper.Decode(noStmt);
|
||||||
|
|
||||||
|
// Now we just parse each individual stmt into the core components and add to statements
|
||||||
|
|
||||||
|
var individualParts = Uri.UnescapeDataString(statements).Split(',').Select(Uri.UnescapeDataString);
|
||||||
|
foreach (var part in individualParts)
|
||||||
|
{
|
||||||
|
filterDto.Statements.Add(new FilterStatementDto()
|
||||||
|
{
|
||||||
|
Value = Regex.Match(part, ValueRegex).Groups["value"].Value,
|
||||||
|
Field = Enum.Parse<FilterField>(Regex.Match(part, FieldRegex).Groups["value"].Value),
|
||||||
|
Comparison = Enum.Parse<FilterComparison>(Regex.Match(part, ComparisonRegex).Groups["value"].Value),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return SmartFilterHelper.Encode(filterDto);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user