Fix enum mapping bugs (#360)

This commit is contained in:
Zoe Roux 2024-03-26 01:24:02 +01:00 committed by GitHub
commit f7603db588
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 84 additions and 73 deletions

View File

@ -4,8 +4,23 @@ WORKDIR /kyoo
COPY .config/dotnet-tools.json .config/dotnet-tools.json COPY .config/dotnet-tools.json .config/dotnet-tools.json
RUN dotnet tool restore RUN dotnet tool restore
COPY Kyoo.sln ./Kyoo.sln
COPY nuget.config ./nuget.config
COPY src/Directory.Build.props src/Directory.Build.props
COPY src/Kyoo.Authentication/Kyoo.Authentication.csproj src/Kyoo.Authentication/Kyoo.Authentication.csproj
COPY src/Kyoo.Abstractions/Kyoo.Abstractions.csproj src/Kyoo.Abstractions/Kyoo.Abstractions.csproj
COPY src/Kyoo.Core/Kyoo.Core.csproj src/Kyoo.Core/Kyoo.Core.csproj
COPY src/Kyoo.Host/Kyoo.Host.csproj src/Kyoo.Host/Kyoo.Host.csproj
COPY src/Kyoo.Postgresql/Kyoo.Postgresql.csproj src/Kyoo.Postgresql/Kyoo.Postgresql.csproj
COPY src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj
COPY src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj
COPY src/Kyoo.Swagger/Kyoo.Swagger.csproj src/Kyoo.Swagger/Kyoo.Swagger.csproj
RUN dotnet restore -a $TARGETARCH
COPY . . COPY . .
RUN dotnet ef migrations bundle --self-contained -f -o /app/migrate -p src/Kyoo.Postgresql --verbose RUN dotnet build
RUN dotnet ef migrations bundle --no-build --self-contained -f -o /app/migrate -p src/Kyoo.Postgresql --verbose
FROM mcr.microsoft.com/dotnet/runtime-deps:8.0 FROM mcr.microsoft.com/dotnet/runtime-deps:8.0
COPY --from=builder /app/migrate /app/migrate COPY --from=builder /app/migrate /app/migrate

View File

@ -79,12 +79,12 @@ public class Movie
/// <summary> /// <summary>
/// A list of tags that match this movie. /// A list of tags that match this movie.
/// </summary> /// </summary>
public string[] Tags { get; set; } = Array.Empty<string>(); public string[] Tags { get; set; } = [];
/// <summary> /// <summary>
/// The list of genres (themes) this show has. /// The list of genres (themes) this show has.
/// </summary> /// </summary>
public Genre[] Genres { get; set; } = Array.Empty<Genre>(); public List<Genre> Genres { get; set; } = [];
/// <summary> /// <summary>
/// Is this show airing, not aired yet or finished? /// Is this show airing, not aired yet or finished?

View File

@ -17,9 +17,15 @@
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>. // along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System; using System;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Text.RegularExpressions;
using Dapper;
using EFCore.NamingConventions.Internal; using EFCore.NamingConventions.Internal;
using InterpolatedSql.SqlBuilders;
using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models;
using Kyoo.Postgresql.Utils;
using Kyoo.Utils;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query.SqlExpressions; using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
@ -42,15 +48,6 @@ public class PostgresContext : DatabaseContext
/// </summary> /// </summary>
private readonly bool _skipConfigure; private readonly bool _skipConfigure;
// TODO: This needs ot be updated but ef-core still does not offer a way to use this.
[Obsolete]
static PostgresContext()
{
NpgsqlConnection.GlobalTypeMapper.MapEnum<Status>();
NpgsqlConnection.GlobalTypeMapper.MapEnum<Genre>();
NpgsqlConnection.GlobalTypeMapper.MapEnum<WatchStatus>();
}
/// <summary> /// <summary>
/// Design time constructor (dotnet ef migrations add). Do not use /// Design time constructor (dotnet ef migrations add). Do not use
/// </summary> /// </summary>
@ -102,11 +99,45 @@ public class PostgresContext : DatabaseContext
"md5", "md5",
args, args,
nullable: true, nullable: true,
argumentsPropagateNullability: new[] { false }, argumentsPropagateNullability: [false],
type: args[0].Type, type: args[0].Type,
typeMapping: args[0].TypeMapping typeMapping: args[0].TypeMapping
)); ));
SqlMapper.TypeMapProvider = (type) =>
{
return new CustomPropertyTypeMap(
type,
(type, name) =>
{
string newName = Regex.Replace(
name,
"(^|_)([a-z])",
(match) => match.Groups[2].Value.ToUpperInvariant()
);
// TODO: Add images handling here (name: poster_source, newName: PosterSource) should set Poster.Source
return type.GetProperty(newName)!;
}
);
};
SqlMapper.AddTypeHandler(
typeof(Dictionary<string, MetadataId>),
new JsonTypeHandler<Dictionary<string, MetadataId>>()
);
SqlMapper.AddTypeHandler(
typeof(Dictionary<string, string>),
new JsonTypeHandler<Dictionary<string, string>>()
);
SqlMapper.AddTypeHandler(
typeof(Dictionary<string, ExternalToken>),
new JsonTypeHandler<Dictionary<string, ExternalToken>>()
);
SqlMapper.AddTypeHandler(typeof(List<string>), new ListTypeHandler<string>());
SqlMapper.AddTypeHandler(typeof(List<Genre>), new ListTypeHandler<Genre>());
SqlMapper.AddTypeHandler(typeof(Wrapper), new Wrapper.Handler());
InterpolatedSqlBuilderOptions.DefaultOptions.ReuseIdenticalParameters = true;
InterpolatedSqlBuilderOptions.DefaultOptions.AutoFixSingleQuotes = false;
base.OnModelCreating(modelBuilder); base.OnModelCreating(modelBuilder);
} }

View File

@ -16,16 +16,9 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>. // along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Data.Common; using System.Data.Common;
using System.Text.RegularExpressions;
using Dapper;
using InterpolatedSql.SqlBuilders;
using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models;
using Kyoo.Postgresql.Utils;
using Kyoo.Utils;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
@ -43,43 +36,6 @@ public class PostgresModule(IConfiguration configuration, IWebHostEnvironment en
/// <inheritdoc /> /// <inheritdoc />
public string Name => "Postgresql"; public string Name => "Postgresql";
static PostgresModule()
{
SqlMapper.TypeMapProvider = (type) =>
{
return new CustomPropertyTypeMap(
type,
(type, name) =>
{
string newName = Regex.Replace(
name,
"(^|_)([a-z])",
(match) => match.Groups[2].Value.ToUpperInvariant()
);
// TODO: Add images handling here (name: poster_source, newName: PosterSource) should set Poster.Source
return type.GetProperty(newName)!;
}
);
};
SqlMapper.AddTypeHandler(
typeof(Dictionary<string, MetadataId>),
new JsonTypeHandler<Dictionary<string, MetadataId>>()
);
SqlMapper.AddTypeHandler(
typeof(Dictionary<string, string>),
new JsonTypeHandler<Dictionary<string, string>>()
);
SqlMapper.AddTypeHandler(
typeof(Dictionary<string, ExternalToken>),
new JsonTypeHandler<Dictionary<string, ExternalToken>>()
);
SqlMapper.AddTypeHandler(typeof(List<string>), new ListTypeHandler<string>());
SqlMapper.AddTypeHandler(typeof(List<Genre>), new ListTypeHandler<Genre>());
SqlMapper.AddTypeHandler(typeof(Wrapper), new Wrapper.Handler());
InterpolatedSqlBuilderOptions.DefaultOptions.ReuseIdenticalParameters = true;
InterpolatedSqlBuilderOptions.DefaultOptions.AutoFixSingleQuotes = false;
}
/// <inheritdoc /> /// <inheritdoc />
public void Configure(IServiceCollection services) public void Configure(IServiceCollection services)
{ {
@ -96,16 +52,24 @@ public class PostgresModule(IConfiguration configuration, IWebHostEnvironment en
["TIMEOUT"] = "30" ["TIMEOUT"] = "30"
}; };
NpgsqlDataSourceBuilder dsBuilder = new(builder.ConnectionString);
dsBuilder.MapEnum<Status>();
dsBuilder.MapEnum<Genre>();
dsBuilder.MapEnum<WatchStatus>();
NpgsqlDataSource dataSource = dsBuilder.Build();
services.AddDbContext<DatabaseContext, PostgresContext>( services.AddDbContext<DatabaseContext, PostgresContext>(
x => x =>
{ {
x.UseNpgsql(builder.ConnectionString).UseProjectables(); x.UseNpgsql(dataSource).UseProjectables();
if (environment.IsDevelopment()) if (environment.IsDevelopment())
x.EnableDetailedErrors().EnableSensitiveDataLogging(); x.EnableDetailedErrors().EnableSensitiveDataLogging();
}, },
ServiceLifetime.Transient ServiceLifetime.Transient
); );
services.AddTransient<DbConnection>((_) => new NpgsqlConnection(builder.ConnectionString)); services.AddTransient(
(services) => services.GetRequiredService<DatabaseContext>().Database.GetDbConnection()
);
services.AddHealthChecks().AddDbContextCheck<DatabaseContext>(); services.AddHealthChecks().AddDbContextCheck<DatabaseContext>();
} }

View File

@ -29,7 +29,7 @@ public class ListTypeHandler<T> : SqlMapper.TypeHandler<List<T>>
public override List<T> Parse(object value) public override List<T> Parse(object value)
{ {
T[] typedValue = (T[])value; // looks like Dapper did not indicate the property type to Npgsql, so it defaults to string[] (default CLR type for text[] PostgreSQL type) T[] typedValue = (T[])value; // looks like Dapper did not indicate the property type to Npgsql, so it defaults to string[] (default CLR type for text[] PostgreSQL type)
return typedValue?.ToList() ?? new(); return typedValue?.ToList() ?? [];
} }
public override void SetValue(IDbDataParameter parameter, List<T>? value) public override void SetValue(IDbDataParameter parameter, List<T>? value)

View File

@ -1,5 +1,5 @@
x-transcoder: &transcoder-base x-transcoder: &transcoder-base
image: zoriya/kyoo_transcoder:edge image: zoriya/kyoo_transcoder:latest
networks: networks:
default: default:
aliases: aliases:
@ -14,7 +14,7 @@ x-transcoder: &transcoder-base
services: services:
back: back:
image: zoriya/kyoo_back:edge image: zoriya/kyoo_back:latest
restart: unless-stopped restart: unless-stopped
cpus: 1.5 cpus: 1.5
env_file: env_file:
@ -32,7 +32,7 @@ services:
- kyoo:/kyoo - kyoo:/kyoo
migrations: migrations:
image: zoriya/kyoo_migrations:edge image: zoriya/kyoo_migrations:latest
restart: "no" restart: "no"
depends_on: depends_on:
postgres: postgres:
@ -41,13 +41,13 @@ services:
- ./.env - ./.env
front: front:
image: zoriya/kyoo_front:edge image: zoriya/kyoo_front:latest
restart: unless-stopped restart: unless-stopped
environment: environment:
- KYOO_URL=${KYOO_URL:-http://back:5000} - KYOO_URL=${KYOO_URL:-http://back:5000}
scanner: scanner:
image: zoriya/kyoo_scanner:edge image: zoriya/kyoo_scanner:latest
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
back: back:

View File

@ -52,14 +52,15 @@ export const ConnectionError = () => {
</View> </View>
); );
} }
if (account.isVerified) return <ErrorView error={error} noBubble />; if (!account.isVerified) {
return ( return (
<View <View
{...css({ flexGrow: 1, flexShrink: 1, justifyContent: "center", alignItems: "center" })} {...css({ flexGrow: 1, flexShrink: 1, justifyContent: "center", alignItems: "center" })}
> >
<P>{t("errors.needVerification")}</P> <P>{t("errors.needVerification")}</P>
</View> </View>
); );
}
} }
return ( return (
<View {...css({ padding: ts(2) })}> <View {...css({ padding: ts(2) })}>