[backend/masto-client] Add edit history endpoint (ISH-274)
This commit is contained in:
parent
10a1a13918
commit
5f86ffeffe
5 changed files with 109 additions and 4 deletions
|
@ -77,8 +77,9 @@ public class MediaController(DriveService driveSvc, DatabaseContext db) : Contro
|
||||||
Blurhash = file.Blurhash,
|
Blurhash = file.Blurhash,
|
||||||
Description = file.Comment,
|
Description = file.Comment,
|
||||||
PreviewUrl = file.ThumbnailUrl,
|
PreviewUrl = file.ThumbnailUrl,
|
||||||
RemoteUrl = file.Uri
|
RemoteUrl = file.Uri,
|
||||||
//Metadata = TODO
|
Sensitive = file.IsSensitive,
|
||||||
|
//Metadata = TODO,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -129,6 +129,57 @@ public class NoteRenderer(
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<StatusEdit>> RenderHistoryAsync(Note note)
|
||||||
|
{
|
||||||
|
var edits = await db.NoteEdits.Where(p => p.Note == note).OrderBy(p => p.Id).ToListAsync();
|
||||||
|
edits.Add(RenderEdit(note));
|
||||||
|
|
||||||
|
var attachments = await GetAttachments(note.FileIds.Concat(edits.SelectMany(p => p.FileIds)));
|
||||||
|
var mentions = await GetMentions([note]);
|
||||||
|
var mentionedUsers = mentions.Select(p => new Note.MentionedUser
|
||||||
|
{
|
||||||
|
Host = p.Host ?? config.Value.AccountDomain,
|
||||||
|
Uri = p.Uri,
|
||||||
|
Username = p.Username,
|
||||||
|
Url = p.Url
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var account = await userRenderer.RenderAsync(note.User);
|
||||||
|
var lastDate = note.CreatedAt;
|
||||||
|
|
||||||
|
List<StatusEdit> history = [];
|
||||||
|
foreach (var edit in edits)
|
||||||
|
{
|
||||||
|
var files = attachments.Where(p => edit.FileIds.Contains(p.Id)).ToList();
|
||||||
|
var entry = new StatusEdit
|
||||||
|
{
|
||||||
|
Account = account,
|
||||||
|
Content = await mfmConverter.ToHtmlAsync(edit.Text ?? "", mentionedUsers, note.UserHost),
|
||||||
|
CreatedAt = lastDate.ToStringIso8601Like(),
|
||||||
|
Emojis = [],
|
||||||
|
IsSensitive = files.Any(p => p.Sensitive),
|
||||||
|
Attachments = files,
|
||||||
|
Poll = null,
|
||||||
|
ContentWarning = edit.Cw ?? ""
|
||||||
|
};
|
||||||
|
history.Add(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return history;
|
||||||
|
}
|
||||||
|
|
||||||
|
private NoteEdit RenderEdit(Note note)
|
||||||
|
{
|
||||||
|
return new NoteEdit
|
||||||
|
{
|
||||||
|
Text = note.Text,
|
||||||
|
Cw = note.Cw,
|
||||||
|
FileIds = note.FileIds,
|
||||||
|
UpdatedAt = note.UpdatedAt ?? note.CreatedAt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private static List<FilterResultEntity> GetFilterResult((Filter filter, string keyword)? filtered)
|
private static List<FilterResultEntity> GetFilterResult((Filter filter, string keyword)? filtered)
|
||||||
{
|
{
|
||||||
if (filtered == null) return [];
|
if (filtered == null) return [];
|
||||||
|
@ -161,7 +212,28 @@ public class NoteRenderer(
|
||||||
Description = f.Comment,
|
Description = f.Comment,
|
||||||
Metadata = null,
|
Metadata = null,
|
||||||
RemoteUrl = f.Uri,
|
RemoteUrl = f.Uri,
|
||||||
Type = AttachmentEntity.GetType(f.Type)
|
Type = AttachmentEntity.GetType(f.Type),
|
||||||
|
Sensitive = f.IsSensitive
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<AttachmentEntity>> GetAttachments(IEnumerable<string> fileIds)
|
||||||
|
{
|
||||||
|
var ids = fileIds.Distinct().ToList();
|
||||||
|
if (ids.Count == 0) return [];
|
||||||
|
return await db.DriveFiles.Where(p => ids.Contains(p.Id))
|
||||||
|
.Select(f => new AttachmentEntity
|
||||||
|
{
|
||||||
|
Id = f.Id,
|
||||||
|
Url = f.PublicUrl,
|
||||||
|
Blurhash = f.Blurhash,
|
||||||
|
PreviewUrl = f.PublicThumbnailUrl,
|
||||||
|
Description = f.Comment,
|
||||||
|
Metadata = null,
|
||||||
|
RemoteUrl = f.Uri,
|
||||||
|
Type = AttachmentEntity.GetType(f.Type),
|
||||||
|
Sensitive = f.IsSensitive
|
||||||
})
|
})
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
|
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
|
||||||
|
using JI = System.Text.Json.Serialization.JsonIgnoreAttribute;
|
||||||
|
|
||||||
namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
|
namespace Iceshrimp.Backend.Controllers.Mastodon.Schemas.Entities;
|
||||||
|
|
||||||
public class AttachmentEntity
|
public class AttachmentEntity
|
||||||
{
|
{
|
||||||
public required AttachmentType Type;
|
[JI] public required bool Sensitive;
|
||||||
|
[JI] public required AttachmentType Type;
|
||||||
[J("id")] public required string Id { get; set; }
|
[J("id")] public required string Id { get; set; }
|
||||||
[J("url")] public required string Url { get; set; }
|
[J("url")] public required string Url { get; set; }
|
||||||
[J("remote_url")] public string? RemoteUrl { get; set; }
|
[J("remote_url")] public string? RemoteUrl { get; set; }
|
||||||
|
|
|
@ -96,3 +96,15 @@ public class StatusSource
|
||||||
[J("text")] public required string Text { get; set; }
|
[J("text")] public required string Text { get; set; }
|
||||||
[J("spoiler_text")] public required string ContentWarning { get; set; }
|
[J("spoiler_text")] public required string ContentWarning { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class StatusEdit
|
||||||
|
{
|
||||||
|
[J("content")] public required string? Content { get; set; }
|
||||||
|
[J("spoiler_text")] public required string ContentWarning { get; set; }
|
||||||
|
[J("sensitive")] public required bool IsSensitive { get; set; }
|
||||||
|
[J("created_at")] public required string CreatedAt { get; set; }
|
||||||
|
[J("account")] public required AccountEntity Account { get; set; }
|
||||||
|
[J("poll")] public required PollEntity? Poll { get; set; }
|
||||||
|
[J("media_attachments")] public required List<AttachmentEntity> Attachments { get; set; }
|
||||||
|
[J("emojis")] public required List<EmojiEntity> Emojis { get; set; }
|
||||||
|
}
|
|
@ -552,4 +552,22 @@ public class StatusController(
|
||||||
|
|
||||||
return Ok(res);
|
return Ok(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id}/history")]
|
||||||
|
[Authenticate("read:statuses")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<AccountEntity>))]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(MastodonErrorResponse))]
|
||||||
|
public async Task<IActionResult> GetNoteEditHistory(string id)
|
||||||
|
{
|
||||||
|
var user = HttpContext.GetUser();
|
||||||
|
var note = await db.Notes
|
||||||
|
.Where(p => p.Id == id)
|
||||||
|
.EnsureVisibleFor(user)
|
||||||
|
.FilterHidden(user, db, filterMutes: false)
|
||||||
|
.FirstOrDefaultAsync() ??
|
||||||
|
throw GracefulException.RecordNotFound();
|
||||||
|
|
||||||
|
var res = await noteRenderer.RenderHistoryAsync(note);
|
||||||
|
return Ok(res);
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue