[backend/masto-client] Add media upload (ISH-58)
This commit is contained in:
parent
589063f36b
commit
a1c23a7d29
5 changed files with 82 additions and 7 deletions
47
Iceshrimp.Backend/Controllers/Mastodon/MediaController.cs
Normal file
47
Iceshrimp.Backend/Controllers/Mastodon/MediaController.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using Iceshrimp.Backend.Controllers.Mastodon.Attributes;
|
||||
using Iceshrimp.Backend.Controllers.Mastodon.Schemas;
|
||||
using Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
|
||||
using Iceshrimp.Backend.Core.Middleware;
|
||||
using Iceshrimp.Backend.Core.Services;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.RateLimiting;
|
||||
|
||||
namespace Iceshrimp.Backend.Controllers.Mastodon;
|
||||
|
||||
[MastodonApiController]
|
||||
[Authenticate]
|
||||
[Authorize("write:media")]
|
||||
[EnableCors("mastodon")]
|
||||
[EnableRateLimiting("sliding")]
|
||||
[Produces("application/json")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Attachment))]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(MastodonErrorResponse))]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(MastodonErrorResponse))]
|
||||
public class MediaController(DriveService driveSvc) : Controller {
|
||||
[HttpPost("/api/v1/media")]
|
||||
[HttpPost("/api/v2/media")]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))]
|
||||
public async Task<IActionResult> UploadAttachment(MediaSchemas.UploadMediaRequest request) {
|
||||
var user = HttpContext.GetUserOrFail();
|
||||
var rq = new DriveFileCreationRequest {
|
||||
Filename = request.File.FileName,
|
||||
IsSensitive = false,
|
||||
Comment = request.Description,
|
||||
MimeType = request.File.ContentType,
|
||||
};
|
||||
var file = await driveSvc.StoreFile(request.File.OpenReadStream(), user, rq);
|
||||
var res = new Attachment {
|
||||
Id = file.Id,
|
||||
Type = Attachment.GetType(file.Type),
|
||||
Url = file.Url,
|
||||
Blurhash = file.Blurhash,
|
||||
Description = file.Comment,
|
||||
PreviewUrl = file.ThumbnailUrl,
|
||||
RemoteUrl = file.Uri,
|
||||
//Metadata = TODO
|
||||
};
|
||||
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas;
|
||||
|
||||
public abstract class MediaSchemas {
|
||||
public class UploadMediaRequest {
|
||||
[FromForm(Name = "file")] public required IFormFile File { get; set; }
|
||||
[FromForm(Name = "description")] public string? Description { get; set; }
|
||||
|
||||
//TODO: add thumbnail & focus properties
|
||||
}
|
||||
}
|
|
@ -92,8 +92,13 @@ public class StatusController(DatabaseContext db, NoteRenderer noteRenderer, Not
|
|||
throw GracefulException.BadRequest("Reply target is nonexistent or inaccessible")
|
||||
: null;
|
||||
|
||||
var note = await noteSvc.CreateNoteAsync(user, visibility, request.Text, request.Cw, reply);
|
||||
var res = await noteRenderer.RenderAsync(note);
|
||||
var attachments = request.MediaIds != null
|
||||
? await db.DriveFiles.Where(p => request.MediaIds.Contains(p.Id)).ToListAsync()
|
||||
: null;
|
||||
|
||||
var note = await noteSvc.CreateNoteAsync(user, visibility, request.Text, request.Cw, reply,
|
||||
attachments: attachments);
|
||||
var res = await noteRenderer.RenderAsync(note);
|
||||
|
||||
return Ok(res);
|
||||
}
|
||||
|
|
|
@ -100,15 +100,19 @@ public class DriveService(
|
|||
|
||||
string? blurhash = null;
|
||||
|
||||
if (request.MimeType.StartsWith("image/")) {
|
||||
if (request.MimeType.StartsWith("image/") || request.MimeType == "image") {
|
||||
try {
|
||||
var image = await Image.LoadAsync<Rgba32>(buf);
|
||||
blurhash = Blurhasher.Encode(image, 7, 7);
|
||||
|
||||
// Correct mime type
|
||||
if (request.MimeType == "image" && image.Metadata.DecodedImageFormat?.DefaultMimeType != null)
|
||||
request.MimeType = image.Metadata.DecodedImageFormat.DefaultMimeType;
|
||||
}
|
||||
catch {
|
||||
logger.LogError("Failed to generate blurhash for image with mime type {type}", request.MimeType);
|
||||
}
|
||||
|
||||
|
||||
buf.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
|
@ -154,7 +158,7 @@ public class DriveService(
|
|||
Url = url,
|
||||
Name = request.Filename,
|
||||
Comment = request.Comment,
|
||||
Type = request.MimeType,
|
||||
Type = CleanMimeType(request.MimeType),
|
||||
RequestHeaders = request.RequestHeaders,
|
||||
RequestIp = request.RequestIp,
|
||||
Blurhash = blurhash,
|
||||
|
|
|
@ -39,8 +39,10 @@ public class NoteService(
|
|||
private readonly List<string> _resolverHistory = [];
|
||||
private int _recursionLimit = 100;
|
||||
|
||||
public async Task<Note> CreateNoteAsync(User user, Note.NoteVisibility visibility, string? text = null,
|
||||
string? cw = null, Note? reply = null, Note? renote = null) {
|
||||
public async Task<Note> CreateNoteAsync(
|
||||
User user, Note.NoteVisibility visibility, string? text = null, string? cw = null, Note? reply = null,
|
||||
Note? renote = null, IReadOnlyCollection<DriveFile>? attachments = null
|
||||
) {
|
||||
if (text?.Length > config.Value.CharacterLimit)
|
||||
throw GracefulException.BadRequest($"Text cannot be longer than {config.Value.CharacterLimit} characters");
|
||||
|
||||
|
@ -52,6 +54,9 @@ public class NoteService(
|
|||
if (text != null)
|
||||
text = mentionsResolver.ResolveMentions(text, null, mentions, splitDomainMapping);
|
||||
|
||||
if (attachments != null && attachments.Any(p => p.UserId != user.Id))
|
||||
throw GracefulException.BadRequest("Refusing to create note with files belonging to someone else");
|
||||
|
||||
var actor = await userRenderer.RenderAsync(user);
|
||||
|
||||
var note = new Note {
|
||||
|
@ -65,6 +70,8 @@ public class NoteService(
|
|||
UserHost = null,
|
||||
Visibility = visibility,
|
||||
|
||||
FileIds = attachments?.Select(p => p.Id).ToList() ?? [],
|
||||
AttachedFileTypes = attachments?.Select(p => p.Type).ToList() ?? [],
|
||||
Mentions = mentionedUserIds,
|
||||
VisibleUserIds = visibility == Note.NoteVisibility.Specified ? mentionedUserIds : [],
|
||||
MentionedRemoteUsers = remoteMentions,
|
||||
|
|
Loading…
Add table
Reference in a new issue