[backend/core] Allow editing of locally originated polls (ISH-136)

This also improves the behavior of handling remotely originating poll edits.
This commit is contained in:
Laura Hausmann 2024-03-07 20:07:17 +01:00
parent 84f7ac7051
commit 57ac4750ad
No known key found for this signature in database
GPG key ID: D044E84C5BE01605
3 changed files with 62 additions and 13 deletions

View file

@ -331,20 +331,29 @@ public class StatusController(
public async Task<IActionResult> EditNote(string id, [FromHybrid] StatusSchemas.EditStatusRequest request) public async Task<IActionResult> EditNote(string id, [FromHybrid] StatusSchemas.EditStatusRequest request)
{ {
var user = HttpContext.GetUserOrFail(); var user = HttpContext.GetUserOrFail();
var note = await db.Notes.IncludeCommonProperties().FirstOrDefaultAsync(p => p.Id == id && p.User == user) ?? var note = await db.Notes
.Include(p => p.Poll)
.IncludeCommonProperties()
.FirstOrDefaultAsync(p => p.Id == id && p.User == user) ??
throw GracefulException.RecordNotFound(); throw GracefulException.RecordNotFound();
if (request.Text == null && request.MediaIds is not { Count: > 0 } && request.Poll == null) if (request.Text == null && request.MediaIds is not { Count: > 0 } && request.Poll == null)
throw GracefulException.BadRequest("Posts must have text, media or poll"); throw GracefulException.BadRequest("Posts must have text, media or poll");
if (request.Poll != null) var poll = request.Poll != null
throw GracefulException.BadRequest("Poll edits haven't been implemented yet, please delete & redraft instead"); ? new Poll
{
Choices = request.Poll.Options,
Multiple = request.Poll.Multiple,
ExpiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(request.Poll.ExpiresIn)
}
: null;
var attachments = request.MediaIds != null var attachments = request.MediaIds != null
? await db.DriveFiles.Where(p => request.MediaIds.Contains(p.Id)).ToListAsync() ? await db.DriveFiles.Where(p => request.MediaIds.Contains(p.Id)).ToListAsync()
: []; : [];
note = await noteSvc.UpdateNoteAsync(note, request.Text, request.Cw, attachments); note = await noteSvc.UpdateNoteAsync(note, request.Text, request.Cw, attachments, poll);
var res = await noteRenderer.RenderAsync(note, user); var res = await noteRenderer.RenderAsync(note, user);
return Ok(res); return Ok(res);

View file

@ -144,7 +144,7 @@ public abstract class BackgroundTaskQueue
var db = scope.GetRequiredService<DatabaseContext>(); var db = scope.GetRequiredService<DatabaseContext>();
var poll = await db.Polls.FirstOrDefaultAsync(p => p.NoteId == job.NoteId, cancellationToken: token); var poll = await db.Polls.FirstOrDefaultAsync(p => p.NoteId == job.NoteId, cancellationToken: token);
if (poll == null) return; if (poll == null) return;
if (poll.ExpiresAt > DateTime.UtcNow + TimeSpan.FromMinutes(5)) return; if (poll.ExpiresAt > DateTime.UtcNow + TimeSpan.FromSeconds(30)) return;
var note = await db.Notes.IncludeCommonProperties() var note = await db.Notes.IncludeCommonProperties()
.FirstOrDefaultAsync(p => p.Id == poll.NoteId, cancellationToken: token); .FirstOrDefaultAsync(p => p.Id == poll.NoteId, cancellationToken: token);
if (note == null) return; if (note == null) return;

View file

@ -208,7 +208,8 @@ public class NoteService(
} }
public async Task<Note> UpdateNoteAsync( public async Task<Note> UpdateNoteAsync(
Note note, string? text = null, string? cw = null, IReadOnlyCollection<DriveFile>? attachments = null Note note, string? text = null, string? cw = null, IReadOnlyCollection<DriveFile>? attachments = null,
Poll? poll = null
) )
{ {
var noteEdit = new NoteEdit var noteEdit = new NoteEdit
@ -268,6 +269,38 @@ public class NoteService(
note.UpdatedAt = DateTime.UtcNow; note.UpdatedAt = DateTime.UtcNow;
if (poll != null)
{
if (note.Poll != null)
{
if (note.Poll.ExpiresAt != poll.ExpiresAt)
{
note.Poll.ExpiresAt = poll.ExpiresAt;
await EnqueuePollExpiryTask(note.Poll);
}
if (!note.Poll.Choices.SequenceEqual(poll.Choices) || note.Poll.Multiple != poll.Multiple)
{
await db.PollVotes.Where(p => p.Note == note).ExecuteDeleteAsync();
note.Poll.Choices = poll.Choices;
note.Poll.Votes = poll.Choices.Select(p => 0).ToList();
note.Poll.Multiple = poll.Multiple;
db.Update(note.Poll);
}
}
else {
poll.Note = note;
poll.UserId = note.User.Id;
poll.UserHost = note.UserHost;
poll.Votes = poll.Choices.Select(_ => 0).ToList();
poll.NoteVisibility = note.Visibility;
await db.AddAsync(poll);
await EnqueuePollExpiryTask(poll);
}
note.HasPoll = true;
}
db.Update(note); db.Update(note);
await db.AddAsync(noteEdit); await db.AddAsync(noteEdit);
await db.SaveChangesAsync(); await db.SaveChangesAsync();
@ -658,13 +691,20 @@ public class NoteService(
if (dbNote.Poll != null) if (dbNote.Poll != null)
{ {
if (!dbNote.Poll.Choices.SequenceEqual(choices.Select(p => p.Name))) if (dbNote.Poll.ExpiresAt != (question.EndTime ?? question.Closed))
{
dbNote.Poll.ExpiresAt = question.EndTime ?? question.Closed;
if (dbNote.Poll.ExpiresAt != null)
await EnqueuePollExpiryTask(dbNote.Poll);
}
if (!dbNote.Poll.Choices.SequenceEqual(choices.Select(p => p.Name)) ||
dbNote.Poll.Multiple != (question.AnyOf != null))
{ {
await db.PollVotes.Where(p => p.Note == dbNote).ExecuteDeleteAsync(); await db.PollVotes.Where(p => p.Note == dbNote).ExecuteDeleteAsync();
dbNote.Poll.Choices = choices.Select(p => p.Name).Cast<string>().ToList(); dbNote.Poll.Choices = choices.Select(p => p.Name).Cast<string>().ToList();
dbNote.Poll.Votes = choices.Select(p => (int?)p.Replies?.TotalItems ?? 0).ToList(); dbNote.Poll.Votes = choices.Select(p => (int?)p.Replies?.TotalItems ?? 0).ToList();
dbNote.Poll.ExpiresAt = question.EndTime ?? question.Closed; dbNote.Poll.Multiple = question.AnyOf != null;
dbNote.Poll.Multiple = question.AnyOf != null;
db.Update(dbNote.Poll); db.Update(dbNote.Poll);
} }
else else