adds application infra and first draft of persistence entities
This commit is contained in:
parent
18124da30f
commit
28f4ec09f2
@ -9,7 +9,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dotnet-ef": {
|
"dotnet-ef": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.10",
|
||||||
"commands": [
|
"commands": [
|
||||||
"dotnet-ef"
|
"dotnet-ef"
|
||||||
]
|
]
|
||||||
|
@ -72,6 +72,7 @@
|
|||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=appsettings/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
17
PiwigoDirectorySync/AppSettings.cs
Normal file
17
PiwigoDirectorySync/AppSettings.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace PiwigoDirectorySync;
|
||||||
|
|
||||||
|
public static class AppSettings
|
||||||
|
{
|
||||||
|
public static IConfigurationRoot Config { get; } = new ConfigurationBuilder().SetBasePath(AppContext.BaseDirectory)
|
||||||
|
.AddJsonFile("appsettings.json", true)
|
||||||
|
.AddJsonFile(Path.Combine(Environment.CurrentDirectory, "appsettings.json"), true)
|
||||||
|
.AddJsonFile("/etc/PiwigoDirectorySync/appsettings.json", true)
|
||||||
|
.AddEnvironmentVariables()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
public static Settings Settings { get; } = Config.GetSection("settings").Get<Settings>() ?? throw new InvalidOperationException("Could not parse settings");
|
||||||
|
|
||||||
|
public static string ConnectionString => Config.GetConnectionString(Settings.DbProvider) ?? throw new InvalidOperationException($"Could not find connection string for provider {Settings.DbProvider}");
|
||||||
|
}
|
37
PiwigoDirectorySync/Commands/ScanCommand.cs
Normal file
37
PiwigoDirectorySync/Commands/ScanCommand.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Threading.Channels;
|
||||||
|
using NLog;
|
||||||
|
using PiwigoDirectorySync.Service;
|
||||||
|
using Spectre.Console.Cli;
|
||||||
|
|
||||||
|
namespace PiwigoDirectorySync.Commands;
|
||||||
|
|
||||||
|
public class ScanCommand : AsyncCommand<ScanSettings>
|
||||||
|
{
|
||||||
|
private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
public override async Task<int> ExecuteAsync(CommandContext context, ScanSettings settings)
|
||||||
|
{
|
||||||
|
Logger.Info("Starting scanner and remover");
|
||||||
|
var stopWatch = Stopwatch.StartNew();
|
||||||
|
|
||||||
|
var cancellationTokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
|
var fileQueue = Channel.CreateUnbounded<string>();
|
||||||
|
|
||||||
|
var indexer = new FileIndexer(fileQueue);
|
||||||
|
var indexerTask = indexer.StartProcessingAsync(cancellationTokenSource.Token);
|
||||||
|
|
||||||
|
var scanner = new FileScanner(fileQueue);
|
||||||
|
await scanner.ScanAsync(cancellationTokenSource.Token);
|
||||||
|
|
||||||
|
fileQueue.Writer.Complete();
|
||||||
|
|
||||||
|
await Task.WhenAll(fileQueue.Reader.Completion, indexerTask);
|
||||||
|
|
||||||
|
stopWatch.Stop();
|
||||||
|
Logger.Info($"Processed {indexer.TotalFilesScanned} image files in {stopWatch.Elapsed.TotalSeconds} seconds");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
7
PiwigoDirectorySync/Commands/ScanSettings.cs
Normal file
7
PiwigoDirectorySync/Commands/ScanSettings.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
using Spectre.Console.Cli;
|
||||||
|
|
||||||
|
namespace PiwigoDirectorySync.Commands;
|
||||||
|
|
||||||
|
public class ScanSettings : CommandSettings
|
||||||
|
{
|
||||||
|
}
|
22
PiwigoDirectorySync/Persistence/AlbumEntity.cs
Normal file
22
PiwigoDirectorySync/Persistence/AlbumEntity.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace PiwigoDirectorySync.Persistence;
|
||||||
|
|
||||||
|
public class AlbumEntity
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public int? ParentId { get; set; }
|
||||||
|
public AlbumEntity? Parent { get; set; }
|
||||||
|
public required int ServerId { get; set; }
|
||||||
|
public PiwigoServerEntity Server { get; set; } = null!;
|
||||||
|
public required string Name { get; set; }
|
||||||
|
public required string DirectoryName { get; set; }
|
||||||
|
public string FullDirectory => Parent is not null ? $"{Parent.FullDirectory}{Path.DirectorySeparatorChar}{DirectoryName}" : DirectoryName;
|
||||||
|
|
||||||
|
public int? PiwigoAlbumId { get; set; }
|
||||||
|
}
|
20
PiwigoDirectorySync/Persistence/ImageEntity.cs
Normal file
20
PiwigoDirectorySync/Persistence/ImageEntity.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace PiwigoDirectorySync.Persistence;
|
||||||
|
|
||||||
|
public class ImageEntity
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
public required string Filename { get; set; }
|
||||||
|
public DateTime LastChange { get; set; }
|
||||||
|
public string? Md5Sum { get; set; }
|
||||||
|
public required int AlbumId { get; set; }
|
||||||
|
public AlbumEntity Album { get; set; } = null!;
|
||||||
|
public int ServerImageId { get; set; }
|
||||||
|
public bool UploadRequired { get; set; }
|
||||||
|
public bool DeleteRequired { get; set; }
|
||||||
|
}
|
25
PiwigoDirectorySync/Persistence/PersistenceContext.cs
Normal file
25
PiwigoDirectorySync/Persistence/PersistenceContext.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace PiwigoDirectorySync.Persistence;
|
||||||
|
|
||||||
|
public class PersistenceContext : DbContext
|
||||||
|
{
|
||||||
|
public DbSet<PiwigoServerEntity> PiwigoServers { get; set; }
|
||||||
|
public DbSet<AlbumEntity> PiwigoAlbums { get; set; }
|
||||||
|
public DbSet<ImageEntity> PiwigoImages { get; set; }
|
||||||
|
|
||||||
|
protected override void OnConfiguring(DbContextOptionsBuilder options)
|
||||||
|
{
|
||||||
|
switch (AppSettings.Settings.DbProvider)
|
||||||
|
{
|
||||||
|
case "Sqlite":
|
||||||
|
options.UseSqlite(AppSettings.ConnectionString);
|
||||||
|
break;
|
||||||
|
case "InMemory":
|
||||||
|
options.UseInMemoryDatabase(AppSettings.ConnectionString);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException($"DbProvider {AppSettings.Settings.DbProvider} is not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
PiwigoDirectorySync/Persistence/PiwigoServerEntity.cs
Normal file
19
PiwigoDirectorySync/Persistence/PiwigoServerEntity.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace PiwigoDirectorySync.Persistence;
|
||||||
|
|
||||||
|
[Index(nameof(Name), IsUnique = true)]
|
||||||
|
public class PiwigoServerEntity
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public required string Name { get; set; }
|
||||||
|
public required string Url { get; set; }
|
||||||
|
public required string Username { get; set; }
|
||||||
|
public required string Password { get; set; }
|
||||||
|
public required string RootDirectory { get; set; }
|
||||||
|
}
|
@ -1,17 +1,46 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<PublishTrimmed>false</PublishTrimmed>
|
||||||
|
<PublishSingleFile>true</PublishSingleFile>
|
||||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
<UserSecretsId>c68c0447-8c7d-4e88-bcc6-96a9853828c7</UserSecretsId>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Piwigo.Client" Version="0.1.0.17"/>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.0"/>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="7.0.0"/>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0"/>
|
||||||
|
<PackageReference Include="NLog.Extensions.Logging" Version="5.2.0"/>
|
||||||
|
<PackageReference Include="Spectre.Console.Analyzer" Version="0.47.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Spectre.Console.Cli" Version="0.47.0"/>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.10">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.10"/>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.10"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="..\.dockerignore">
|
<Content Include="..\.dockerignore">
|
||||||
<Link>.dockerignore</Link>
|
<Link>.dockerignore</Link>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,3 +1,15 @@
|
|||||||
// See https://aka.ms/new-console-template for more information
|
using NLog;
|
||||||
|
using NLog.Extensions.Logging;
|
||||||
|
using PiwigoDirectorySync;
|
||||||
|
using PiwigoDirectorySync.Commands;
|
||||||
|
using Spectre.Console.Cli;
|
||||||
|
|
||||||
Console.WriteLine("Hello, World!");
|
LogManager.Configuration = new NLogLoggingConfiguration(AppSettings.Config.GetSection("NLog"));
|
||||||
|
var logFactory = LogManager.Setup().LogFactory;
|
||||||
|
var logger = logFactory.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
logger.Info("Starting command app");
|
||||||
|
var app = new CommandApp();
|
||||||
|
app.Configure(c => { c.AddCommand<ScanCommand>("scan"); });
|
||||||
|
|
||||||
|
return app.Run(args);
|
17
PiwigoDirectorySync/Service/FileIndexer.cs
Normal file
17
PiwigoDirectorySync/Service/FileIndexer.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using System.Threading.Channels;
|
||||||
|
|
||||||
|
namespace PiwigoDirectorySync.Service;
|
||||||
|
|
||||||
|
public class FileIndexer
|
||||||
|
{
|
||||||
|
private readonly Channel<string> _fileQueue;
|
||||||
|
|
||||||
|
public FileIndexer(Channel<string> fileQueue)
|
||||||
|
{
|
||||||
|
_fileQueue = fileQueue ?? throw new ArgumentNullException(nameof(fileQueue));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int TotalFilesScanned { get; }
|
||||||
|
|
||||||
|
public Task StartProcessingAsync(CancellationToken token) => throw new NotImplementedException();
|
||||||
|
}
|
15
PiwigoDirectorySync/Service/FileScanner.cs
Normal file
15
PiwigoDirectorySync/Service/FileScanner.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using System.Threading.Channels;
|
||||||
|
|
||||||
|
namespace PiwigoDirectorySync.Service;
|
||||||
|
|
||||||
|
public class FileScanner
|
||||||
|
{
|
||||||
|
private readonly Channel<string> _fileQueue;
|
||||||
|
|
||||||
|
public FileScanner(Channel<string> fileQueue)
|
||||||
|
{
|
||||||
|
_fileQueue = fileQueue ?? throw new ArgumentNullException(nameof(fileQueue));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ScanAsync(CancellationToken token) => throw new NotImplementedException();
|
||||||
|
}
|
9
PiwigoDirectorySync/Settings.cs
Normal file
9
PiwigoDirectorySync/Settings.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace PiwigoDirectorySync;
|
||||||
|
|
||||||
|
public class Settings
|
||||||
|
{
|
||||||
|
public string DbProvider { get; set; } = null!;
|
||||||
|
public string ImageRootDirectory { get; set; } = null!;
|
||||||
|
|
||||||
|
public bool HasErrors => string.IsNullOrEmpty(DbProvider) || string.IsNullOrEmpty(ImageRootDirectory);
|
||||||
|
}
|
5
PiwigoDirectorySync/addMigration.ps1
Normal file
5
PiwigoDirectorySync/addMigration.ps1
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
$comment=$args[0]
|
||||||
|
|
||||||
|
write-host "adding migration for Sqlite"
|
||||||
|
dotnet ef migrations add --project PiwigoDirectorySync.csproj --startup-project PiwigoDirectorySync.csproj --context PiwigoDirectorySync.Persistence.PersistenceContext "$comment" --output-dir Migrations -- --DbProvider Sqlite
|
||||||
|
#dotnet ef migrations add --project PiwigoDirectorySync/PiwigoDirectorySync.csproj --startup-project PiwigoDirectorySync/PiwigoDirectorySync.csproj --context PiwigoDirectorySync.Persistence.Persistence.PersistenceContext "$comment" --output-dir Migrations -- --DbProvider Sqlite
|
68
PiwigoDirectorySync/appsettings.json
Normal file
68
PiwigoDirectorySync/appsettings.json
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Debug",
|
||||||
|
"System": "Information",
|
||||||
|
"Microsoft": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"Sqlite": "Data Source=piwigoSync.db",
|
||||||
|
"InMemory": "InMemorySyncDb"
|
||||||
|
},
|
||||||
|
"Settings": {
|
||||||
|
"DbProvider": "Sqlite",
|
||||||
|
"ImageRootDirectory": ".\\"
|
||||||
|
},
|
||||||
|
"NLog": {
|
||||||
|
"autoReload": true,
|
||||||
|
"throwConfigExceptions": true,
|
||||||
|
"default-wrapper": {
|
||||||
|
"type": "AsyncWrapper",
|
||||||
|
"overflowAction": "Block"
|
||||||
|
},
|
||||||
|
"targets": {
|
||||||
|
"cli-console": {
|
||||||
|
"type": "ColoredConsole",
|
||||||
|
"layout": "${longdate} | ${uppercase:${level}} | ${logger} | ${message} ${exception:format=tostring}",
|
||||||
|
"rowHighlightingRules": [
|
||||||
|
{
|
||||||
|
"condition": "level == LogLevel.Trace",
|
||||||
|
"foregroundColor": "DarkGray"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"condition": "level == LogLevel.Debug",
|
||||||
|
"foregroundColor": "White"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"condition": "level == LogLevel.Info",
|
||||||
|
"foregroundColor": "DarkGreen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"condition": "level == LogLevel.Warn",
|
||||||
|
"foregroundColor": "Yellow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"condition": "level == LogLevel.Error",
|
||||||
|
"foregroundColor": "DarkMagenta"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"condition": "level == LogLevel.Fatal",
|
||||||
|
"foregroundColor": "DarkRed"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"logger": "*",
|
||||||
|
"minLevel": "Info",
|
||||||
|
"writeTo": "cli-console"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"logger": "Microsoft.*",
|
||||||
|
"maxLevel": "Info"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
34
README.md
34
README.md
@ -1,2 +1,36 @@
|
|||||||
# PiwigoDirectorySync
|
# PiwigoDirectorySync
|
||||||
|
|
||||||
|
This application synchronizes the local directory structure with piwigo servers.
|
||||||
|
Each directory level gets created as album or sub album in piwigo.
|
||||||
|
|
||||||
|
## Building / tooling
|
||||||
|
|
||||||
|
### Restoring dotnet tools
|
||||||
|
|
||||||
|
In the root path you may just run the command ``dotnet tool restore`` to install all dotnet tools and extensions used in this project.
|
||||||
|
|
||||||
|
### Handle development secrets
|
||||||
|
|
||||||
|
To make sure no local development db configuration gets committed, we use the dotnet-user-secrets tool.
|
||||||
|
|
||||||
|
When you configure your environment for the first time and you do not like the default settings, use the following commands to set the secrets:
|
||||||
|
|
||||||
|
``
|
||||||
|
cd PiwigoDirectorySync
|
||||||
|
dotnet user-secrets set "DbProvider" "MariaDb"
|
||||||
|
dotnet user-secrets set "ConnectionStrings:MariaDb" "Server=localhost;User Id=photowfdev;Password=password123;Database=photowfdev"
|
||||||
|
``
|
||||||
|
|
||||||
|
You'll find your secrets under `~/.microsoft/usersecrets/c68c0447-8c7d-4e88-bcc6-96a9853828c7/secrets.json`
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
Build the application and docker image for hosting using docker.
|
||||||
|
|
||||||
|
TODO: add some docker build details
|
||||||
|
|
||||||
|
### Publish
|
||||||
|
|
||||||
|
Build the application for manual installation using publish.
|
||||||
|
|
||||||
|
TODO: add some publish details
|
Loading…
Reference in New Issue
Block a user