Implement file upload

This commit is contained in:
2025-11-20 09:55:57 +09:00
parent 7c5c889c53
commit 5b3cb2cabd
9 changed files with 128 additions and 16 deletions

View File

@ -22,7 +22,7 @@
<RadzenAlert Visible="@hasError" AlertStyle="AlertStyle.Danger" Variant="Variant.Flat" Shade="Shade.Lighter" AllowClose="false"> <RadzenAlert Visible="@hasError" AlertStyle="AlertStyle.Danger" Variant="Variant.Flat" Shade="Shade.Lighter" AllowClose="false">
@errorMessage @errorMessage
</RadzenAlert> </RadzenAlert>
<RadzenUpload id="uploadWithDragAndDrop" @ref="upload" Url="upload-to-parse" Progress="@OnProgress" Complete="@OnCompleteAsync" ChooseText="Перетащите сюда или нажмите, чтобы выбрать файл" Auto="false" Multiple="false" Style="width: 100%;" /> <RadzenUpload id="uploadWithDragAndDrop" @ref="upload" Url="upload/parsing" Progress="@OnProgress" Complete="@OnCompleteAsync" ChooseText="Перетащите сюда или нажмите, чтобы выбрать файл" Accept=".xlsx" Auto="false" Multiple="false" Style="width: 100%;" />
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" JustifyContent="JustifyContent.End" Gap="0.5rem"> <RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" JustifyContent="JustifyContent.End" Gap="0.5rem">
<RadzenButton Click="@Upload" Visible="@(state == UploadState.Idle)" Text="Отправить" /> <RadzenButton Click="@Upload" Visible="@(state == UploadState.Idle)" Text="Отправить" />
<RadzenButton Click="@Close" Visible="@(state == UploadState.Idle)" ButtonStyle="ButtonStyle.Light" Text="Отмена" /> <RadzenButton Click="@Close" Visible="@(state == UploadState.Idle)" ButtonStyle="ButtonStyle.Light" Text="Отмена" />
@ -44,6 +44,10 @@
int progress; int progress;
bool hasError; bool hasError;
string errorMessage; string errorMessage;
int? fileToParseId;
[Parameter]
public required string UploaderId { get; set; }
void Upload() void Upload()
{ {
@ -55,7 +59,7 @@
void Close() void Close()
{ {
DialogService.Close(true); DialogService.Close(fileToParseId);
} }
void OnProgress(UploadProgressArgs args) void OnProgress(UploadProgressArgs args)
@ -67,7 +71,13 @@
{ {
try try
{ {
// TODO var root = args.JsonResponse.RootElement;
var fileToParse = await FileToParseService.AddFileToParseAsync(
root.GetProperty("Path").GetString(),
root.GetProperty("FileName").GetString(),
UploaderId,
DateTime.Now);
fileToParseId = fileToParse.Id;
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -1,6 +1,7 @@
using Hcs.WebApp.BackgroundServices; using Hcs.WebApp.BackgroundServices;
using Hcs.WebApp.Components.Dialogs; using Hcs.WebApp.Components.Dialogs;
using Hcs.WebApp.Data.Hcs; using Hcs.WebApp.Data.Hcs;
using Hcs.WebApp.Data.Hcs.CampaignArgs;
using Hcs.WebApp.Services; using Hcs.WebApp.Services;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Authorization;
@ -74,7 +75,7 @@ namespace Hcs.WebApp.Components.Shared
if (await HeadquartersService.HasActiveCampaignAsync(CampaignType)) if (await HeadquartersService.HasActiveCampaignAsync(CampaignType))
{ {
ChangeState(SyncedPageState.Idle); ChangeState(SyncedPageState.SyncWaiting);
} }
else else
{ {
@ -88,17 +89,19 @@ namespace Hcs.WebApp.Components.Shared
{ {
if (state == SyncedPageState.SyncWaiting) return; if (state == SyncedPageState.SyncWaiting) return;
ChangeState(SyncedPageState.SyncWaiting);
if (await HeadquartersService.HasActiveCampaignAsync(CampaignType)) if (await HeadquartersService.HasActiveCampaignAsync(CampaignType))
{ {
ChangeState(SyncedPageState.Idle); ChangeState(SyncedPageState.SyncWaiting);
} }
else else
{ {
await DialogService.OpenAsync<StartParsing>( var dialogResult = await DialogService.OpenAsync<StartParsing>(
"Отправка файла", "Отправка файла",
null, new Dictionary<string, object>()
{
// TODO: Use user id
{ nameof(StartParsing.UploaderId), "" }
},
new DialogOptions() new DialogOptions()
{ {
Width = "600px", Width = "600px",
@ -107,9 +110,18 @@ namespace Hcs.WebApp.Components.Shared
ShowClose = false ShowClose = false
}); });
//// TODO: Use user id var fileToParseId = -1;
//var campaign = await HeadquartersService.InitiateCampaignAsync(CampaignType, ""); if (dialogResult != null && int.TryParse(dialogResult, out fileToParseId))
//CampaignManagementState.EnqueueCampaign(campaign); {
// TODO: Use user id
var campaign = await HeadquartersService.InitiateCampaignAsync(CampaignType, "", new CampaignParseArgs()
{
FileToParseId = fileToParseId
});
CampaignManagementState.EnqueueCampaign(campaign);
ChangeState(SyncedPageState.SyncWaiting);
}
} }
} }

View File

@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Hcs.WebApp.Controllers
{
[Authorize]
[DisableRequestSizeLimit]
public class UploadController(IWebHostEnvironment environment) : Controller
{
private readonly IWebHostEnvironment environment = environment;
[HttpPost("upload/parsing")]
public IActionResult Single(IFormFile file)
{
try
{
var fileName = $"{DateTime.Today:dd-MM-yyyy}-{Guid.NewGuid()}{Path.GetExtension(file.FileName)}";
using var stream = new FileStream(Path.Combine(environment.WebRootPath, fileName), FileMode.Create);
file.CopyTo(stream);
return Ok(new
{
Path = Url.Content($"~/{fileName}"),
FileName = file.FileName
});
}
catch (Exception e)
{
return StatusCode(500, e.Message);
}
}
}
}

View File

@ -1,4 +1,6 @@
using System.ComponentModel.DataAnnotations; using Hcs.WebApp.Data.Hcs.CampaignArgs;
using Newtonsoft.Json;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
namespace Hcs.WebApp.Data.Hcs namespace Hcs.WebApp.Data.Hcs
@ -35,9 +37,29 @@ namespace Hcs.WebApp.Data.Hcs
public string? FailureReason { get; set; } public string? FailureReason { get; set; }
public string? Args { get; set; }
public virtual ICollection<Operation>? Operations { get; set; } = null; public virtual ICollection<Operation>? Operations { get; set; } = null;
[NotMapped] [NotMapped]
public bool Completed => EndedAt.HasValue; public bool Completed => EndedAt.HasValue;
public ICampaignArgs? DeserializeArgs()
{
if (Args == null) return null;
return JsonConvert.DeserializeObject<ICampaignArgs>(Args, new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Auto
});
}
public void SerializeArgs(ICampaignArgs args)
{
Args = JsonConvert.SerializeObject(args, Formatting.None, new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Auto
});
}
} }
} }

View File

@ -0,0 +1,7 @@
namespace Hcs.WebApp.Data.Hcs.CampaignArgs
{
public class CampaignParseArgs : ICampaignArgs
{
public int FileToParseId;
}
}

View File

@ -0,0 +1,5 @@
namespace Hcs.WebApp.Data.Hcs.CampaignArgs
{
// Маркер
public interface ICampaignArgs { }
}

View File

@ -8,9 +8,9 @@
public string FileName { get; set; } public string FileName { get; set; }
public int UploaderId { get; set; } public string UploaderId { get; set; }
public DateTime? UploadedAt { get; set; } public DateTime UploadedAt { get; set; }
public DateTime? ParsedAt { get; set; } public DateTime? ParsedAt { get; set; }

View File

@ -10,5 +10,21 @@ namespace Hcs.WebApp.Services
using var context = GetNewContext(); using var context = GetNewContext();
return await context.FilesToParse.ToListAsync(); return await context.FilesToParse.ToListAsync();
} }
public async Task<FileToParse> AddFileToParseAsync(string path, string fileName, string uploaderId, DateTime uploadedAt)
{
using var context = GetNewContext();
var fileToParse = new FileToParse()
{
Path = path,
FileName = fileName,
UploaderId = uploaderId,
UploadedAt = uploadedAt
};
await context.FilesToParse.AddAsync(fileToParse);
await context.SaveChangesAsync();
return fileToParse;
}
} }
} }

View File

@ -1,4 +1,5 @@
using Hcs.WebApp.Data.Hcs; using Hcs.WebApp.Data.Hcs;
using Hcs.WebApp.Data.Hcs.CampaignArgs;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace Hcs.WebApp.Services namespace Hcs.WebApp.Services
@ -69,7 +70,7 @@ namespace Hcs.WebApp.Services
select operation).ToListAsync(); select operation).ToListAsync();
} }
public async Task<Campaign> InitiateCampaignAsync(Campaign.CampaignType type, string initiatorId) public async Task<Campaign> InitiateCampaignAsync(Campaign.CampaignType type, string initiatorId, ICampaignArgs? args = null)
{ {
using var context = GetNewContext(); using var context = GetNewContext();
var campaign = new Campaign() var campaign = new Campaign()
@ -78,6 +79,12 @@ namespace Hcs.WebApp.Services
InitiatorId = initiatorId, InitiatorId = initiatorId,
CreatedAt = DateTime.UtcNow CreatedAt = DateTime.UtcNow
}; };
if (args != null)
{
campaign.SerializeArgs(args);
}
await context.Campaigns.AddAsync(campaign); await context.Campaigns.AddAsync(campaign);
await context.SaveChangesAsync(); await context.SaveChangesAsync();
return campaign; return campaign;