Use InMemory db driver at testing

This commit is contained in:
Paul Schneider 2026-05-28 22:18:26 +01:00
commit 95dec3636a
24 changed files with 474 additions and 139 deletions

View file

@ -4,9 +4,10 @@
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>1c73094f-959f-4211-b1a1-6a69b236c283</UserSecretsId>
<RootNamespace>Yavsc.Api</RootNamespace>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
<ProjectReference Include="../Yavsc.Server/Yavsc.Server.csproj" />
</ItemGroup>
</Project>
</Project>

View file

@ -115,7 +115,7 @@ namespace Yavsc.ApiControllers
}
if (Request.Form.Files.Count!=1)
return new BadRequestResult();
User.ReceiveProSignature(billingCode,id,Request.Form.Files[0],"pro");
await User.ReceiveProSignatureAsync(billingCode,id,Request.Form.Files[0],"pro");
estimate.ProviderValidationDate = DateTime.Now;
dbContext.SaveChanges(User.GetUserId());
// Notify the client
@ -160,7 +160,7 @@ namespace Yavsc.ApiControllers
}
if (Request.Form.Files.Count!=1)
return new BadRequestResult();
User.ReceiveProSignature(billingCode,id,Request.Form.Files[0],"cli");
await User.ReceiveProSignatureAsync(billingCode,id,Request.Form.Files[0],"cli");
estimate.ClientValidationDate = DateTime.Now;
dbContext.SaveChanges(User.GetUserId());
return Ok (new { ClientValidationDate = estimate.ClientValidationDate });

View file

@ -66,12 +66,15 @@ namespace Yavsc.WebApi.Controllers
/// Updates the avatar
/// </summary>
/// <returns></returns>
[HttpPost("~/api/setavatar")]
[HttpPost("~/api/set-avatar")]
public async Task<IActionResult> SetAvatar()
{
var user = await GetUserData(User.GetUserId());
if (Request.Form.Files.Count!=1)
return new BadRequestResult();
if (!Request.Form.Files[0].ContentType.StartsWith("image/png"))
return new BadRequestResult();
var info = user.ReceiveAvatar(Request.Form.Files[0]);
await _dbContext.SaveChangesAsync();
return Ok(info);

12
src/PostIt/App.axaml Normal file
View file

@ -0,0 +1,12 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="PostIt.App"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
<Application.Styles>
<FluentTheme />
<StyleInclude Source="avares://AvaloniaEdit/Themes/Fluent/AvaloniaEdit.xaml" />
</Application.Styles>
</Application>

23
src/PostIt/App.axaml.cs Normal file
View file

@ -0,0 +1,23 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
namespace PostIt;
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow();
}
base.OnFrameworkInitializationCompleted();
}
}

View file

@ -0,0 +1,27 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:AvaloniaEdit="clr-namespace:AvaloniaEdit;assembly=AvaloniaEdit"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="PostIt.MainWindow"
Title="PostIt">
<Window.Content>
<StackPanel>
<Label>Welcome to Avalonia !!!</Label>
<Label x:Name="Greeting">
Hello !
</Label>
<AvaloniaEdit:TextEditor
ShowLineNumbers="True"
FontFamily="Cascadia Code,Consolas,Menlo,Monospace"
Background="AliceBlue"
Foreground="Black"
Watermark="Hit me strong!"
/>
</StackPanel>
</Window.Content>
</Window>

View file

@ -0,0 +1,12 @@
using Avalonia.Controls;
namespace PostIt;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Greeting.Content="Hello Joe!";
}
}

21
src/PostIt/PostIt.csproj Normal file
View file

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ApplicationManifest>app.manifest</ApplicationManifest>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia" />
<PackageReference Include="Avalonia.AvaloniaEdit" />
<PackageReference Include="Avalonia.Desktop" />
<PackageReference Include="Avalonia.Themes.Fluent" />
<PackageReference Include="Avalonia.Fonts.Inter" />
<PackageReference Include="AvaloniaUI.DiagnosticsSupport">
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
</PackageReference>
<PackageReference Include="Yavsc.Abstract" />
</ItemGroup>
</Project>

24
src/PostIt/Program.cs Normal file
View file

@ -0,0 +1,24 @@
using Avalonia;
using System;
namespace PostIt;
class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
#if DEBUG
.WithDeveloperTools()
#endif
.WithInterFont()
.LogToTrace();
}

18
src/PostIt/app.manifest Normal file
View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embedded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="PostIt.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>

View file

@ -6,8 +6,9 @@
</Description>
<RootNamespace>Yavsc.Abstract</RootNamespace>
<RepositoryUrl>https://github.com/pazof/yavsc</RepositoryUrl>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" />
</ItemGroup>
</Project>
</Project>

View file

@ -5,9 +5,10 @@
<UserSecretsId>1c73094f-959f-4211-b1a1-6a69b236c283</UserSecretsId>
<RootNamespace>Yavsc.Api</RootNamespace>
<RepositoryUrl>https://github.com/pazof/yavsc</RepositoryUrl>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
<ProjectReference Include="../Yavsc.Server/Yavsc.Server.csproj" />
</ItemGroup>
</Project>
</Project>

View file

@ -37,6 +37,7 @@ namespace Yavsc.Extensions;
public static class HostingExtensions
{
private const string InMemoryProviderName = "InMemory";
public static WebApplication ConfigureWebAppServices(this WebApplicationBuilder builder)
{
@ -140,11 +141,19 @@ public static class HostingExtensions
public static IdentityBuilder AddIdentityDBAndStores(this WebApplicationBuilder builder)
{
IServiceCollection services = builder.Services;
var connectionString = builder.Configuration.GetConnectionString(Constants.YavscConnectionStringName);
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseNpgsql(builder.Configuration.GetConnectionString(Constants.YavscConnectionStringName),
options => options.MigrationsAssembly(typeof(Program).Assembly));
if (UsesInMemoryProvider(connectionString))
{
options.UseInMemoryDatabase(connectionString);
}
else
{
options.UseNpgsql(connectionString,
options => options.MigrationsAssembly(typeof(Program).Assembly));
}
});
var identityBuilder = services.AddIdentity<ApplicationUser, IdentityRole>(
@ -285,14 +294,35 @@ public static class HostingExtensions
.AddResourceStore<ResourceStore>()
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b => b.UseNpgsql(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly))
.UseSeeding(EnsureDefaultApplicationScopes());
options.ConfigureDbContext = b =>
{
if (UsesInMemoryProvider(connectionString))
{
b.UseInMemoryDatabase(connectionString);
}
else
{
b.UseNpgsql(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
}
b.UseSeeding(EnsureDefaultApplicationScopes());
};
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b => b.UseNpgsql(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
options.ConfigureDbContext = b =>
{
if (UsesInMemoryProvider(connectionString))
{
b.UseInMemoryDatabase(connectionString);
}
else
{
b.UseNpgsql(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
}
};
});
@ -303,6 +333,11 @@ public static class HostingExtensions
return identityServerBuilder;
}
private static bool UsesInMemoryProvider(string connectionString)
{
return string.Equals(connectionString, InMemoryProviderName, StringComparison.OrdinalIgnoreCase);
}
private static Action<DbContext, bool> EnsureDefaultApplicationScopes()
{
return (context, _) =>

View file

@ -5,7 +5,7 @@
<PackageLicenseExpression>WTFPL</PackageLicenseExpression>
<UserSecretsId>76e56fc2-1619-40d8-8393-365258b7a21d</UserSecretsId>
<RootNamespace>Yavsc</RootNamespace>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<RepositoryUrl>https://github.com/pazof/yavsc</RepositoryUrl>
</PropertyGroup>
<ItemGroup>
@ -21,7 +21,6 @@
<PackageReference Include="HigginsSoft.IdentityServer8.EntityFramework.Storage" />
<PackageReference Include="HigginsSoft.IdentityServer8.Security" />
<PackageReference Include="HigginsSoft.IdentityServer8.Storage" />
<PackageReference Include="Serilog.AspNetCore" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" />
@ -33,6 +32,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" />
<PackageReference Include="Google.Apis.Compute.v1" />
@ -44,7 +44,6 @@
<PackageReference Include="Swashbuckle.AspNetCore" />
<PackageReference Include="AsciiDocSharp" />
<PackageReference Include="AsciiDocSharp.Converters.Html" />
<PackageReference Include="SixLabors.ImageSharp" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" />
<PackageReference Include="Microsoft.Extensions.Logging" />
</ItemGroup>

View file

@ -7,38 +7,34 @@ using Yavsc.Models;
using Yavsc.Models.FileSystem;
using Yavsc.Models.Streaming;
using Yavsc.ViewModels;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using Microsoft.AspNetCore.Http;
using Yavsc.Exceptions;
using Yavsc.Helpers;
using Yavsc.Abstract.Helpers;
using ImageMagick;
namespace Yavsc.Server.Helpers
{
public static class FileSystemHelpers
public static class FileSystemHelpers
{
public static async Task SaveAsAsync(this IFormFile formFile, string path)
{
if (formFile.Length > 0) {
using (Stream fileStream = new FileStream(path, FileMode.Create)) {
if (formFile.Length > 0)
{
using (Stream fileStream = new FileStream(path, FileMode.Create))
{
await formFile.CopyToAsync(fileStream);
}
}
}
public static FileReceivedInfo ReceiveProSignature(this ClaimsPrincipal user, string billingCode, long estimateId, IFormFile formFile, string signType)
public static async Task<FileReceivedInfo> ReceiveProSignatureAsync(this ClaimsPrincipal user, string billingCode, long estimateId, IFormFile formFile, string signType)
{
var item = new FileReceivedInfo(
Config.SiteSetup.Bills,
Config.SiteSetup.Bills,
AbstractFileSystemHelpers.SignFileNameFormat("pro", billingCode, estimateId));
var fi = new FileInfo(item.FullName);
if (fi.Exists) item.Overridden = true;
using (var org = formFile.OpenReadStream())
{
using Image image = Image.Load(org);
image.Save(fi.FullName);
}
await formFile.SaveAsAsync(fi.FullName);
return item;
}
@ -76,67 +72,70 @@ namespace Yavsc.Server.Helpers
{
var root = Path.Combine(AbstractFileSystemHelpers.UserFilesDirName, user.UserName);
var fi = new FileInfo(Path.Combine(root, fileName));
if (!fi.Exists) return ;
if (!fi.Exists) return;
fi.Delete();
user.DiskUsage -= fi.Length;
}
public static FsOperationInfo DeleteUserDirOrFile(this ApplicationUser user, string dirName)
{
var root = Path.Combine(AbstractFileSystemHelpers.UserFilesDirName, user.UserName);
if (string.IsNullOrEmpty(dirName))
return new FsOperationInfo { Done = false, ErrorCode = ErrorCode.InvalidRequest, ErrorMessage = "specify a directory or file name"} ;
if (string.IsNullOrEmpty(dirName))
return new FsOperationInfo { Done = false, ErrorCode = ErrorCode.InvalidRequest, ErrorMessage = "specify a directory or file name" };
var di = new DirectoryInfo(Path.Combine(root, dirName));
if (!di.Exists) {
if (!di.Exists)
{
var fi = new FileInfo(Path.Combine(root, dirName));
if (!fi.Exists) return new FsOperationInfo { Done = false, ErrorCode = ErrorCode.NotFound, ErrorMessage = "non existent"} ;
if (!fi.Exists) return new FsOperationInfo { Done = false, ErrorCode = ErrorCode.NotFound, ErrorMessage = "non existent" };
fi.Delete();
user.DiskUsage -= fi.Length;
}
else {
if (di.GetDirectories().Length>0 || di.GetFiles().Length>0)
return new FsOperationInfo { Done = false, ErrorCode = ErrorCode.InvalidRequest, ErrorMessage = "dir is not empty, refusing to remove it"} ;
else
{
if (di.GetDirectories().Length > 0 || di.GetFiles().Length > 0)
return new FsOperationInfo { Done = false, ErrorCode = ErrorCode.InvalidRequest, ErrorMessage = "dir is not empty, refusing to remove it" };
di.Delete();
}
return new FsOperationInfo { Done = true };
}
public static FsOperationInfo MoveUserDir(this ApplicationUser user, string fromDirName, string toDirName)
{
var root = Path.Combine(AbstractFileSystemHelpers.UserFilesDirName, user.UserName);
if (string.IsNullOrEmpty(fromDirName))
return new FsOperationInfo { Done = false, ErrorCode = ErrorCode.InvalidRequest , ErrorMessage = "specify a dir name "} ;
if (string.IsNullOrEmpty(fromDirName))
return new FsOperationInfo { Done = false, ErrorCode = ErrorCode.InvalidRequest, ErrorMessage = "specify a dir name " };
var di = new DirectoryInfo(Path.Combine(root, fromDirName));
if (!di.Exists) return new FsOperationInfo { Done = false, ErrorCode = ErrorCode.NotFound, ErrorMessage = "fromDirName: non existent"} ;
if (!di.Exists) return new FsOperationInfo { Done = false, ErrorCode = ErrorCode.NotFound, ErrorMessage = "fromDirName: non existent" };
if (string.IsNullOrEmpty(toDirName)) toDirName = ".";
var destPath = Path.Combine(root, toDirName);
var fout = new FileInfo(destPath);
if (fout.Exists) return new FsOperationInfo { Done = false, ErrorCode = ErrorCode.InvalidRequest, ErrorMessage = "destination is a regular file" } ;
if (fout.Exists) return new FsOperationInfo { Done = false, ErrorCode = ErrorCode.InvalidRequest, ErrorMessage = "destination is a regular file" };
var dout = new DirectoryInfo(destPath);
if (dout.Exists) {
destPath = Path.Combine(destPath, dout.Name);
var dOut = new DirectoryInfo(destPath);
if (dOut.Exists)
{
destPath = Path.Combine(destPath, dOut.Name);
}
di.MoveTo(destPath);
di.MoveTo(destPath);
return new FsOperationInfo { Done = true };
}
public static FsOperationInfo MoveUserFileToDir(this ApplicationUser user, string fileNameFrom, string fileNameDest)
{
var root = Path.Combine(AbstractFileSystemHelpers.UserFilesDirName, user.UserName);
var fi = new FileInfo(Path.Combine(root, fileNameFrom));
if (!fi.Exists) return new FsOperationInfo { ErrorCode = ErrorCode.NotFound, ErrorMessage = "no file to move" } ;
if (!fi.Exists) return new FsOperationInfo { ErrorCode = ErrorCode.NotFound, ErrorMessage = "no file to move" };
string dest;
if (!string.IsNullOrEmpty(fileNameDest)) dest = Path.Combine(root, fileNameDest);
else dest = root;
var fo = new FileInfo(dest);
if (fo.Exists) return new FsOperationInfo { ErrorCode = ErrorCode.DestExists , ErrorMessage = "destination file name is an existing file" } ;
if (fo.Exists) return new FsOperationInfo { ErrorCode = ErrorCode.DestExists, ErrorMessage = "destination file name is an existing file" };
var dout = new DirectoryInfo(dest);
if (!dout.Exists) dout.Create();
fi.MoveTo(Path.Combine(dout.FullName, fi.Name));
@ -146,9 +145,9 @@ namespace Yavsc.Server.Helpers
{
var root = Path.Combine(AbstractFileSystemHelpers.UserFilesDirName, user.UserName);
var fi = new FileInfo(Path.Combine(root, fileNameFrom));
if (!fi.Exists) return new FsOperationInfo { ErrorCode = ErrorCode.NotFound, ErrorMessage = "no file to move" } ;
if (!fi.Exists) return new FsOperationInfo { ErrorCode = ErrorCode.NotFound, ErrorMessage = "no file to move" };
var fo = new FileInfo(Path.Combine(root, fileNameDest));
if (fo.Exists) return new FsOperationInfo { ErrorCode = ErrorCode.DestExists , ErrorMessage = "destination file name is an existing file" } ;
if (fo.Exists) return new FsOperationInfo { ErrorCode = ErrorCode.DestExists, ErrorMessage = "destination file name is an existing file" };
fi.MoveTo(fo.FullName);
return new FsOperationInfo { Done = true };
}
@ -158,7 +157,7 @@ namespace Yavsc.Server.Helpers
// form-data_ name=_file__ filename=_Constants.Private.cs_
var parts = disposition.Split(' ');
var filename = parts[2].Split('=')[1];
filename = filename.Substring(1,filename.Length-2);
filename = filename.Substring(1, filename.Length - 2);
return filename;
}
@ -170,7 +169,7 @@ namespace Yavsc.Server.Helpers
{
return ReceiveUserFile(user, root, f.OpenReadStream(), destFileName ?? ParseFileNameFromDisposition(f.ContentDisposition), f.ContentType, CancellationToken.None);
}
/// <summary>
/// Modifies the user's disk usage
/// </summary>
@ -203,7 +202,7 @@ namespace Yavsc.Server.Helpers
{
item.Overridden = true;
usage -= fi.Length;
}
}
using (var dest = fi.OpenWrite())
{
using (inputStream)
@ -211,7 +210,7 @@ namespace Yavsc.Server.Helpers
const int blen = 1024;
byte[] buffer = new byte[blen];
int len = 0;
while (!token.IsCancellationRequested && (len=inputStream.Read(buffer, 0, blen))>0)
while (!token.IsCancellationRequested && (len = inputStream.Read(buffer, 0, blen)) > 0)
{
dest.Write(buffer, 0, len);
usage += len;
@ -222,7 +221,8 @@ namespace Yavsc.Server.Helpers
inputStream.Close();
}
}
if (usage >= user.DiskQuota) {
if (usage >= user.DiskQuota)
{
item.QuotaOffense = true;
}
user.DiskUsage = usage;
@ -231,15 +231,15 @@ namespace Yavsc.Server.Helpers
public static HtmlString FileLink(this RemoteFileInfo info, string username, string subpath)
{
return new HtmlString(
$"{Config.UserFilesOptions.RequestPath}/{username}/{subpath}/{info.Name}" );
return new HtmlString(
$"{Config.UserFilesOptions.RequestPath}/{username}/{subpath}/{info.Name}");
}
public static RemoteFileInfo FileInfo(this ApplicationUser user, string path)
{
IFileInfo info = Config.UserFilesOptions.FileProvider.GetFileInfo($"{user.UserName}/{path}");
if (!info.Exists) return null;
return new RemoteFileInfo{ Name = info.Name, Size = info.Length, LastModified = info.LastModified.UtcDateTime };
return new RemoteFileInfo { Name = info.Name, Size = info.Length, LastModified = info.LastModified.UtcDateTime };
}
@ -248,32 +248,43 @@ namespace Yavsc.Server.Helpers
var item = new FileReceivedInfo
(Config.AvatarsOptions.RequestPath.ToUriComponent(),
user.UserName + ".png");
using (var org = formFile.OpenReadStream())
{
using Image image = Image.Load(org);
image.Mutate(x=>x.Resize(128,128));
image.Save(Path.Combine(Config.SiteSetup.Avatars,item.FileName));
image.Mutate(x=>x.Resize(64,64));
image.Save(Path.Combine(Config.SiteSetup.Avatars,user.UserName + ".s.png"));
image.Mutate(x=>x.Resize(32,32));
image.Save(Path.Combine(Config.SiteSetup.Avatars,user.UserName + ".xs.png"));
var size = new MagickGeometry(128, 128);
size.IgnoreAspectRatio = false;
using var image = new MagickImage(org);
image.Resize(size);
image.Write(Path.Combine(Config.SiteSetup.Avatars, item.FileName));
size.X = 64;
size.Y = 64;
image.Resize(size);
image.Write(Path.Combine(Config.SiteSetup.Avatars, user.UserName + ".s.png"));
size.X = 32;
size.Y = 32;
image.Resize(size);
image.Write(Path.Combine(Config.SiteSetup.Avatars, user.UserName + ".xs.png"));
}
user.Avatar = $"{item.DestDir}/{item.FileName}";
return item;
}
public static string GetFileUrl (this LiveFlow flow)
public static string GetFileUrl(this LiveFlow flow)
{
// no server-side backup for this stream
return $"{Config.UserFilesOptions.RequestPath}/{flow.Owner.UserName}/live/"+GetFileName(flow);
return $"{Config.UserFilesOptions.RequestPath}/{flow.Owner.UserName}/live/" + GetFileName(flow);
}
public static string GetFileName (this LiveFlow flow)
public static string GetFileName(this LiveFlow flow)
{
var fileInfo = new FileInfo(flow.DifferedFileName);
var ext = fileInfo.Extension;
var namelen = flow.DifferedFileName.Length - ext.Length;
var basename = flow.DifferedFileName.Substring(0,namelen);
var basename = flow.DifferedFileName.Substring(0, namelen);
return $"{basename}-{flow.SequenceNumber}{ext}";
}

View file

@ -4,10 +4,12 @@
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>53bd70e8-ff81-497a-847f-a15fd8ea7a09</UserSecretsId>
<RootNamespace>Yavsc.Server</RootNamespace>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<RepositoryUrl>https://github.com/pazof/yavsc</RepositoryUrl>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="HigginsSoft.IdentityServer8.EntityFramework" />
<PackageReference Include="Magick.NET-Q8-AnyCPU" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" />
<PackageReference Include="HigginsSoft.IdentityServer8" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" />
@ -22,7 +24,6 @@
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" />
<PackageReference Include="Google.Apis.Calendar.v3" />
<PackageReference Include="PayPalMerchantSDK" />
<PackageReference Include="SixLabors.ImageSharp" />
<PackageReference Include="RazorEngine.NetCore" />
<PackageReference Include="MailKit" />
<PackageReference Include="MimeKit" />
@ -31,4 +32,4 @@
<ItemGroup>
<ProjectReference Include="../Yavsc.Abstract/Yavsc.Abstract.csproj" />
</ItemGroup>
</Project>
</Project>

View file

@ -15,4 +15,4 @@
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
</Project>
</Project>

View file

@ -4,6 +4,7 @@
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>Yavsc.cli</RootNamespace>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Razor" />
@ -18,4 +19,4 @@
<ProjectReference Include="..\Yavsc.Abstract\Yavsc.Abstract.csproj" />
<ProjectReference Include="..\Yavsc.Server\Yavsc.Server.csproj" />
</ItemGroup>
</Project>
</Project>