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">
@errorMessage
</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">
<RadzenButton Click="@Upload" Visible="@(state == UploadState.Idle)" Text="Отправить" />
<RadzenButton Click="@Close" Visible="@(state == UploadState.Idle)" ButtonStyle="ButtonStyle.Light" Text="Отмена" />
@ -44,6 +44,10 @@
int progress;
bool hasError;
string errorMessage;
int? fileToParseId;
[Parameter]
public required string UploaderId { get; set; }
void Upload()
{
@ -55,7 +59,7 @@
void Close()
{
DialogService.Close(true);
DialogService.Close(fileToParseId);
}
void OnProgress(UploadProgressArgs args)
@ -67,7 +71,13 @@
{
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)
{

View File

@ -1,6 +1,7 @@
using Hcs.WebApp.BackgroundServices;
using Hcs.WebApp.Components.Dialogs;
using Hcs.WebApp.Data.Hcs;
using Hcs.WebApp.Data.Hcs.CampaignArgs;
using Hcs.WebApp.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
@ -74,7 +75,7 @@ namespace Hcs.WebApp.Components.Shared
if (await HeadquartersService.HasActiveCampaignAsync(CampaignType))
{
ChangeState(SyncedPageState.Idle);
ChangeState(SyncedPageState.SyncWaiting);
}
else
{
@ -88,17 +89,19 @@ namespace Hcs.WebApp.Components.Shared
{
if (state == SyncedPageState.SyncWaiting) return;
ChangeState(SyncedPageState.SyncWaiting);
if (await HeadquartersService.HasActiveCampaignAsync(CampaignType))
{
ChangeState(SyncedPageState.Idle);
ChangeState(SyncedPageState.SyncWaiting);
}
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()
{
Width = "600px",
@ -107,9 +110,18 @@ namespace Hcs.WebApp.Components.Shared
ShowClose = false
});
//// TODO: Use user id
//var campaign = await HeadquartersService.InitiateCampaignAsync(CampaignType, "");
//CampaignManagementState.EnqueueCampaign(campaign);
var fileToParseId = -1;
if (dialogResult != null && int.TryParse(dialogResult, out fileToParseId))
{
// 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;
namespace Hcs.WebApp.Data.Hcs
@ -35,9 +37,29 @@ namespace Hcs.WebApp.Data.Hcs
public string? FailureReason { get; set; }
public string? Args { get; set; }
public virtual ICollection<Operation>? Operations { get; set; } = null;
[NotMapped]
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 int UploaderId { get; set; }
public string UploaderId { get; set; }
public DateTime? UploadedAt { get; set; }
public DateTime UploadedAt { get; set; }
public DateTime? ParsedAt { get; set; }

View File

@ -10,5 +10,21 @@ namespace Hcs.WebApp.Services
using var context = GetNewContext();
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.CampaignArgs;
using Microsoft.EntityFrameworkCore;
namespace Hcs.WebApp.Services
@ -69,7 +70,7 @@ namespace Hcs.WebApp.Services
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();
var campaign = new Campaign()
@ -78,6 +79,12 @@ namespace Hcs.WebApp.Services
InitiatorId = initiatorId,
CreatedAt = DateTime.UtcNow
};
if (args != null)
{
campaign.SerializeArgs(args);
}
await context.Campaigns.AddAsync(campaign);
await context.SaveChangesAsync();
return campaign;