submit gifs by URL:
UI (Submit.razor) - Toggle zwischen "Datei" und "URL" Modus - URL-Eingabefeld mit Validierung (nur HTTP/HTTPS) - Beide Modi teilen Submit-Button und Erfolgsanzeige Service (IClubGifService, ClubGifService) - Neue Methode SubmitAnonymousFromUrlAsync(token, url, name) - Nutzt bestehende SaveGifFromUrlAsync von MediaStorageService Serverseitige Validierung (bereits in MediaStorageService vorhanden): - Content-Type Prüfung: nur image/gif, video/mp4, video/webm - Dateigröße max. 20MB - Datei wird nach Download nochmals auf Größe geprüft - Ungültige Content-Types werden mit Exception abgelehnt
This commit is contained in:
parent
968026729d
commit
3b12a82982
|
|
@ -36,6 +36,7 @@ public interface IClubGifService
|
|||
|
||||
// Anonymous Submission
|
||||
Task<ClubGifDto> SubmitAnonymousAsync(string token, IFormFile file, string name, CancellationToken ct = default);
|
||||
Task<ClubGifDto> SubmitAnonymousFromUrlAsync(string token, string url, string name, CancellationToken ct = default);
|
||||
|
||||
// Template Seeding
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -285,6 +285,40 @@ public class ClubGifService : IClubGifService
|
|||
return MapToDto(gif, club.LoginName);
|
||||
}
|
||||
|
||||
public async Task<ClubGifDto> SubmitAnonymousFromUrlAsync(string token, string url, string name, CancellationToken ct = default)
|
||||
{
|
||||
var tokenEntity = await _repository.GetSubmissionTokenAsync(token, ct)
|
||||
?? throw new ArgumentException("Invalid or expired token");
|
||||
|
||||
if (!tokenEntity.IsValid)
|
||||
throw new ArgumentException("Token is expired or usage limit reached");
|
||||
|
||||
var club = await _clubRepository.GetByIdAsync(tokenEntity.ClubId, ct)
|
||||
?? throw new ArgumentException("Club not found");
|
||||
|
||||
var (fileName, contentType) = await _mediaStorage.SaveGifFromUrlAsync(club.LoginName, url, ct);
|
||||
var fileInfo = new FileInfo(Path.Combine("wwwroot", "club-media", club.LoginName, "gifs", fileName));
|
||||
|
||||
var gif = new ClubGif
|
||||
{
|
||||
ClubId = tokenEntity.ClubId,
|
||||
Name = name,
|
||||
FileName = fileName,
|
||||
OriginalFileName = Path.GetFileName(new Uri(url).LocalPath),
|
||||
ContentType = contentType,
|
||||
FileSizeBytes = fileInfo.Exists ? fileInfo.Length : 0,
|
||||
SourceUrl = url,
|
||||
AssignedEvents = ThrowEventType.None,
|
||||
IsEnabled = false,
|
||||
IsPendingApproval = true
|
||||
};
|
||||
|
||||
gif = await _repository.AddAsync(gif, ct);
|
||||
await _repository.IncrementSubmissionCountAsync(tokenEntity.Id, ct);
|
||||
|
||||
return MapToDto(gif, club.LoginName);
|
||||
}
|
||||
|
||||
public async Task<int> SeedTemplateGifsAsync(Guid clubId, CancellationToken ct = default)
|
||||
{
|
||||
var club = await _clubRepository.GetByIdAsync(clubId, ct)
|
||||
|
|
|
|||
|
|
@ -78,34 +78,67 @@
|
|||
Variant="Variant.Outlined"
|
||||
Class="mb-2" />
|
||||
|
||||
<MudFileUpload T="IBrowserFile"
|
||||
Accept=".gif,.mp4,.webm"
|
||||
FilesChanged="OnFileSelected"
|
||||
MaximumFileCount="1"
|
||||
Class="mb-4">
|
||||
<ActivatorContent>
|
||||
<MudPaper Outlined="true"
|
||||
Class="pa-4 d-flex flex-column align-center justify-center"
|
||||
Style="border-style: dashed; min-height: 120px; cursor: pointer;">
|
||||
@if (_selectedFile != null)
|
||||
{
|
||||
<MudIcon Icon="@Icons.Material.Filled.InsertDriveFile" Size="Size.Large" Color="Color.Success" />
|
||||
<MudText Typo="Typo.body1">@_selectedFile.Name</MudText>
|
||||
<MudText Typo="Typo.caption" Color="Color.Secondary">
|
||||
@FormatFileSize(_selectedFile.Size)
|
||||
</MudText>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudIcon Icon="@Icons.Material.Filled.CloudUpload" Size="Size.Large" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.body1">Datei auswaehlen</MudText>
|
||||
<MudText Typo="Typo.caption" Color="Color.Secondary">
|
||||
GIF, MP4 oder WebM (max. 20MB)
|
||||
</MudText>
|
||||
}
|
||||
</MudPaper>
|
||||
</ActivatorContent>
|
||||
</MudFileUpload>
|
||||
<MudButtonGroup OverrideStyles="false" Class="mb-4" Style="width: 100%;">
|
||||
<MudButton Variant="@(_useUrl ? Variant.Outlined : Variant.Filled)"
|
||||
Color="Color.Primary"
|
||||
Style="flex: 1;"
|
||||
OnClick="() => SetUploadMode(false)">
|
||||
<MudIcon Icon="@Icons.Material.Filled.UploadFile" Class="mr-1" Size="Size.Small" />
|
||||
Datei
|
||||
</MudButton>
|
||||
<MudButton Variant="@(_useUrl ? Variant.Filled : Variant.Outlined)"
|
||||
Color="Color.Primary"
|
||||
Style="flex: 1;"
|
||||
OnClick="() => SetUploadMode(true)">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Link" Class="mr-1" Size="Size.Small" />
|
||||
URL
|
||||
</MudButton>
|
||||
</MudButtonGroup>
|
||||
|
||||
@if (_useUrl)
|
||||
{
|
||||
<MudTextField @bind-Value="_url"
|
||||
Label="URL zum GIF/Video"
|
||||
Placeholder="https://example.com/animation.gif"
|
||||
Required="true"
|
||||
Variant="Variant.Outlined"
|
||||
InputType="InputType.Url"
|
||||
Adornment="Adornment.Start"
|
||||
AdornmentIcon="@Icons.Material.Filled.Link"
|
||||
Class="mb-2"
|
||||
HelperText="Direkt-Link zu GIF, MP4 oder WebM" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudFileUpload T="IBrowserFile"
|
||||
Accept=".gif,.mp4,.webm"
|
||||
FilesChanged="OnFileSelected"
|
||||
MaximumFileCount="1"
|
||||
Class="mb-4">
|
||||
<ActivatorContent>
|
||||
<MudPaper Outlined="true"
|
||||
Class="pa-4 d-flex flex-column align-center justify-center"
|
||||
Style="border-style: dashed; min-height: 120px; cursor: pointer;">
|
||||
@if (_selectedFile != null)
|
||||
{
|
||||
<MudIcon Icon="@Icons.Material.Filled.InsertDriveFile" Size="Size.Large" Color="Color.Success" />
|
||||
<MudText Typo="Typo.body1">@_selectedFile.Name</MudText>
|
||||
<MudText Typo="Typo.caption" Color="Color.Secondary">
|
||||
@FormatFileSize(_selectedFile.Size)
|
||||
</MudText>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudIcon Icon="@Icons.Material.Filled.CloudUpload" Size="Size.Large" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.body1">Datei auswaehlen</MudText>
|
||||
<MudText Typo="Typo.caption" Color="Color.Secondary">
|
||||
GIF, MP4 oder WebM (max. 20MB)
|
||||
</MudText>
|
||||
}
|
||||
</MudPaper>
|
||||
</ActivatorContent>
|
||||
</MudFileUpload>
|
||||
}
|
||||
|
||||
@if (_previewUrl != null)
|
||||
{
|
||||
|
|
@ -167,8 +200,33 @@
|
|||
private bool _isSubmitting;
|
||||
private bool _isSubmitted;
|
||||
private string? _error;
|
||||
private bool _useUrl;
|
||||
private string _url = "";
|
||||
|
||||
private bool CanSubmit => !string.IsNullOrWhiteSpace(_name) && _selectedFile != null;
|
||||
private bool CanSubmit => !string.IsNullOrWhiteSpace(_name) &&
|
||||
(_useUrl ? IsValidUrl(_url) : _selectedFile != null);
|
||||
|
||||
private static bool IsValidUrl(string url)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(url)) return false;
|
||||
return Uri.TryCreate(url, UriKind.Absolute, out var uri) &&
|
||||
(uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps);
|
||||
}
|
||||
|
||||
private void SetUploadMode(bool useUrl)
|
||||
{
|
||||
_useUrl = useUrl;
|
||||
_error = null;
|
||||
if (useUrl)
|
||||
{
|
||||
_selectedFile = null;
|
||||
_previewUrl = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_url = "";
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
|
|
@ -208,20 +266,27 @@
|
|||
|
||||
private async Task SubmitGif()
|
||||
{
|
||||
if (!CanSubmit || _selectedFile == null) return;
|
||||
if (!CanSubmit) return;
|
||||
|
||||
_isSubmitting = true;
|
||||
_error = null;
|
||||
|
||||
try
|
||||
{
|
||||
using var stream = _selectedFile.OpenReadStream(maxAllowedSize: 20 * 1024 * 1024);
|
||||
using var ms = new MemoryStream();
|
||||
await stream.CopyToAsync(ms);
|
||||
ms.Position = 0;
|
||||
if (_useUrl)
|
||||
{
|
||||
await GifService.SubmitAnonymousFromUrlAsync(Token, _url, _name);
|
||||
}
|
||||
else if (_selectedFile != null)
|
||||
{
|
||||
using var stream = _selectedFile.OpenReadStream(maxAllowedSize: 20 * 1024 * 1024);
|
||||
using var ms = new MemoryStream();
|
||||
await stream.CopyToAsync(ms);
|
||||
ms.Position = 0;
|
||||
|
||||
var formFile = new FormFileFromStream(ms, _selectedFile.Name, _selectedFile.ContentType);
|
||||
await GifService.SubmitAnonymousAsync(Token, formFile, _name);
|
||||
var formFile = new FormFileFromStream(ms, _selectedFile.Name, _selectedFile.ContentType);
|
||||
await GifService.SubmitAnonymousAsync(Token, formFile, _name);
|
||||
}
|
||||
|
||||
_isSubmitted = true;
|
||||
Snackbar.Add("GIF erfolgreich eingereicht!", Severity.Success);
|
||||
|
|
@ -244,6 +309,8 @@
|
|||
_selectedFile = null;
|
||||
_previewUrl = null;
|
||||
_error = null;
|
||||
_url = "";
|
||||
_useUrl = false;
|
||||
}
|
||||
|
||||
private static string FormatFileSize(long bytes)
|
||||
|
|
|
|||
Loading…
Reference in New Issue