[backend/api] Add renote endpoints (ISH-341)
This commit is contained in:
parent
835796ac86
commit
167fd5f0d6
4 changed files with 78 additions and 15 deletions
|
@ -294,7 +294,6 @@ public class StatusController(
|
||||||
var note = await db.Notes.Where(p => p.Id == id)
|
var note = await db.Notes.Where(p => p.Id == id)
|
||||||
.IncludeCommonProperties()
|
.IncludeCommonProperties()
|
||||||
.EnsureVisibleFor(user)
|
.EnsureVisibleFor(user)
|
||||||
.FilterHidden(user, db, filterMutes: false)
|
|
||||||
.FirstOrDefaultAsync() ??
|
.FirstOrDefaultAsync() ??
|
||||||
throw GracefulException.RecordNotFound();
|
throw GracefulException.RecordNotFound();
|
||||||
|
|
||||||
|
@ -302,10 +301,8 @@ public class StatusController(
|
||||||
? StatusEntity.DecodeVisibility(request.Visibility)
|
? StatusEntity.DecodeVisibility(request.Visibility)
|
||||||
: user.UserSettings?.DefaultRenoteVisibility ?? Note.NoteVisibility.Public;
|
: user.UserSettings?.DefaultRenoteVisibility ?? Note.NoteVisibility.Public;
|
||||||
|
|
||||||
if (renoteVisibility == Note.NoteVisibility.Specified)
|
renote = await noteSvc.RenoteNoteAsync(note, user, renoteVisibility) ??
|
||||||
throw GracefulException.BadRequest("Renote visibility must be one of: public, unlisted, private");
|
throw new Exception("Created renote was null");
|
||||||
|
|
||||||
renote = await noteSvc.CreateNoteAsync(user, renoteVisibility, renote: note);
|
|
||||||
note.RenoteCount++; // we do not want to call save changes after this point
|
note.RenoteCount++; // we do not want to call save changes after this point
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,17 +316,14 @@ public class StatusController(
|
||||||
public async Task<IActionResult> UndoRenote(string id)
|
public async Task<IActionResult> UndoRenote(string id)
|
||||||
{
|
{
|
||||||
var user = HttpContext.GetUserOrFail();
|
var user = HttpContext.GetUserOrFail();
|
||||||
if (!await db.Notes.Where(p => p.Id == id).EnsureVisibleFor(user).AnyAsync())
|
var note = await db.Notes.Where(p => p.Id == id)
|
||||||
throw GracefulException.RecordNotFound();
|
.IncludeCommonProperties()
|
||||||
|
.EnsureVisibleFor(user)
|
||||||
var renotes = await db.Notes.Where(p => p.RenoteId == id && p.IsPureRenote && p.User == user)
|
.FirstOrDefaultAsync() ??
|
||||||
.IncludeCommonProperties()
|
throw GracefulException.RecordNotFound();
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
foreach (var renote in renotes) await noteSvc.DeleteNoteAsync(renote);
|
|
||||||
|
|
||||||
renotes[0].Renote!.RenoteCount--; // we do not want to call save changes after this point
|
|
||||||
|
|
||||||
|
var count = await noteSvc.UnrenoteNoteAsync(note, user);
|
||||||
|
note.RenoteCount -= (short)count; // we do not want to call save changes after this point
|
||||||
return await GetNote(id);
|
return await GetNote(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -170,6 +170,40 @@ public class NoteController(
|
||||||
return Ok(new ValueResponse(success ? --note.LikeCount : note.LikeCount));
|
return Ok(new ValueResponse(success ? --note.LikeCount : note.LikeCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost("{id}/renote")]
|
||||||
|
[Authenticate]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ValueResponse))]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ErrorResponse))]
|
||||||
|
public async Task<IActionResult> RenoteNote(string id, [FromQuery] NoteVisibility? visibility = null)
|
||||||
|
{
|
||||||
|
var user = HttpContext.GetUserOrFail();
|
||||||
|
var note = await db.Notes.Where(p => p.Id == id)
|
||||||
|
.EnsureVisibleFor(user)
|
||||||
|
.FirstOrDefaultAsync() ??
|
||||||
|
throw GracefulException.NotFound("Note not found");
|
||||||
|
|
||||||
|
var success = await noteSvc.RenoteNoteAsync(note, user, (Note.NoteVisibility?)visibility);
|
||||||
|
return Ok(new ValueResponse(success != null ? ++note.RenoteCount : note.RenoteCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("{id}/unrenote")]
|
||||||
|
[Authenticate]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ValueResponse))]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ErrorResponse))]
|
||||||
|
public async Task<IActionResult> UnrenoteNote(string id)
|
||||||
|
{
|
||||||
|
var user = HttpContext.GetUserOrFail();
|
||||||
|
var note = await db.Notes.Where(p => p.Id == id)
|
||||||
|
.EnsureVisibleFor(user)
|
||||||
|
.FirstOrDefaultAsync() ??
|
||||||
|
throw GracefulException.NotFound("Note not found");
|
||||||
|
|
||||||
|
var count = await noteSvc.UnrenoteNoteAsync(note, user);
|
||||||
|
return Ok(new ValueResponse(note.RenoteCount - count));
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost("{id}/react/{name}")]
|
[HttpPost("{id}/react/{name}")]
|
||||||
[Authenticate]
|
[Authenticate]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
|
|
|
@ -1105,6 +1105,31 @@ public class NoteService(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<Note?> RenoteNoteAsync(Note note, User user, Note.NoteVisibility? visibility = null)
|
||||||
|
{
|
||||||
|
visibility ??= user.UserSettings?.DefaultRenoteVisibility ?? Note.NoteVisibility.Public;
|
||||||
|
if (visibility == Note.NoteVisibility.Specified)
|
||||||
|
throw GracefulException.BadRequest("Renote visibility must be one of: public, unlisted, private");
|
||||||
|
if (note.IsPureRenote)
|
||||||
|
throw GracefulException.BadRequest("Cannot renote a pure renote");
|
||||||
|
|
||||||
|
if (!await db.Notes.AnyAsync(p => p.Renote == note && p.IsPureRenote && p.User == user))
|
||||||
|
return await CreateNoteAsync(user, visibility.Value, renote: note);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> UnrenoteNoteAsync(Note note, User user)
|
||||||
|
{
|
||||||
|
var renotes = await db.Notes.Where(p => p.Renote == note && p.IsPureRenote && p.User == user).ToListAsync();
|
||||||
|
if (renotes.Count == 0) return 0;
|
||||||
|
|
||||||
|
foreach (var renote in renotes)
|
||||||
|
await DeleteNoteAsync(renote);
|
||||||
|
|
||||||
|
return renotes.Count;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task LikeNoteAsync(ASNote note, User actor)
|
public async Task LikeNoteAsync(ASNote note, User actor)
|
||||||
{
|
{
|
||||||
var dbNote = await ResolveNoteAsync(note) ?? throw new Exception("Cannot register like for unknown note");
|
var dbNote = await ResolveNoteAsync(note) ?? throw new Exception("Cannot register like for unknown note");
|
||||||
|
|
|
@ -34,6 +34,16 @@ internal class NoteControllerModel(ApiClient api)
|
||||||
public Task<ValueResponse?> UnlikeNote(string id) =>
|
public Task<ValueResponse?> UnlikeNote(string id) =>
|
||||||
api.CallNullable<ValueResponse>(HttpMethod.Post, $"/notes/{id}/unlike");
|
api.CallNullable<ValueResponse>(HttpMethod.Post, $"/notes/{id}/unlike");
|
||||||
|
|
||||||
|
public Task<ValueResponse?> RenoteNote(string id, NoteVisibility? visibility = null)
|
||||||
|
{
|
||||||
|
var query = new QueryString();
|
||||||
|
if (visibility.HasValue) query.Add("visibility", ((int)visibility.Value).ToString().ToLowerInvariant());
|
||||||
|
return api.CallNullable<ValueResponse>(HttpMethod.Post, $"/notes/{id}/renote", query);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ValueResponse?> UnrenoteNote(string id) =>
|
||||||
|
api.CallNullable<ValueResponse>(HttpMethod.Post, $"/notes/{id}/unrenote");
|
||||||
|
|
||||||
public Task<ValueResponse?> ReactToNote(string id, string name) =>
|
public Task<ValueResponse?> ReactToNote(string id, string name) =>
|
||||||
api.CallNullable<ValueResponse>(HttpMethod.Post, $"/notes/{id}/react/{name}");
|
api.CallNullable<ValueResponse>(HttpMethod.Post, $"/notes/{id}/react/{name}");
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue