✨ Poll answer and un-answer
This commit is contained in:
@@ -20,6 +20,28 @@ public class Poll : ModelBase
|
|||||||
public Publisher.Publisher Publisher { get; set; } = null!;
|
public Publisher.Publisher Publisher { get; set; } = null!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PollWithUserAnswer : Poll
|
||||||
|
{
|
||||||
|
public PollAnswer? UserAnswer { get; set; }
|
||||||
|
|
||||||
|
public static PollWithUserAnswer FromPoll(Poll poll, PollAnswer? userAnswer = null)
|
||||||
|
{
|
||||||
|
return new PollWithUserAnswer
|
||||||
|
{
|
||||||
|
Id = poll.Id,
|
||||||
|
Title = poll.Title,
|
||||||
|
Description = poll.Description,
|
||||||
|
EndedAt = poll.EndedAt,
|
||||||
|
PublisherId = poll.PublisherId,
|
||||||
|
Publisher = poll.Publisher,
|
||||||
|
Questions = poll.Questions,
|
||||||
|
CreatedAt = poll.CreatedAt,
|
||||||
|
UpdatedAt = poll.UpdatedAt,
|
||||||
|
UserAnswer = userAnswer
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public enum PollQuestionType
|
public enum PollQuestionType
|
||||||
{
|
{
|
||||||
SingleChoice,
|
SingleChoice,
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Text.Json;
|
||||||
using DysonNetwork.Shared.Proto;
|
using DysonNetwork.Shared.Proto;
|
||||||
using DysonNetwork.Sphere.Publisher;
|
using DysonNetwork.Sphere.Publisher;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
@@ -11,6 +12,63 @@ namespace DysonNetwork.Sphere.Poll;
|
|||||||
[Route("/api/polls")]
|
[Route("/api/polls")]
|
||||||
public class PollController(AppDatabase db, PollService polls, PublisherService pub) : ControllerBase
|
public class PollController(AppDatabase db, PollService polls, PublisherService pub) : ControllerBase
|
||||||
{
|
{
|
||||||
|
[HttpGet("{id:guid}")]
|
||||||
|
public async Task<ActionResult<PollWithUserAnswer>> GetPoll(Guid id)
|
||||||
|
{
|
||||||
|
var poll = await db.Polls
|
||||||
|
.Include(p => p.Questions)
|
||||||
|
.FirstOrDefaultAsync(p => p.Id == id);
|
||||||
|
if (poll is null) return NotFound("Poll not found");
|
||||||
|
var pollWithAnswer = PollWithUserAnswer.FromPoll(poll);
|
||||||
|
|
||||||
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Ok(pollWithAnswer);
|
||||||
|
|
||||||
|
var accountId = Guid.Parse(currentUser.Id);
|
||||||
|
var answer = await polls.GetPollAnswer(id, accountId);
|
||||||
|
if (answer is not null)
|
||||||
|
pollWithAnswer.UserAnswer = answer;
|
||||||
|
|
||||||
|
return Ok(pollWithAnswer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PollAnswerRequest
|
||||||
|
{
|
||||||
|
public required Dictionary<string, JsonElement> Answer { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("{id:guid}/answer")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<ActionResult<PollAnswer>> AnswerPoll(Guid id, [FromBody] PollAnswerRequest request)
|
||||||
|
{
|
||||||
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
var accountId = Guid.Parse(currentUser.Id);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await polls.AnswerPoll(id, accountId, request.Answer);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return BadRequest(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{id:guid}/answer")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<IActionResult> DeletePollAnswer(Guid id)
|
||||||
|
{
|
||||||
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
var accountId = Guid.Parse(currentUser.Id);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await polls.UnAnswerPoll(id, accountId);
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return BadRequest(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet("me")]
|
[HttpGet("me")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<ActionResult<List<Poll>>> ListPolls(
|
public async Task<ActionResult<List<Poll>>> ListPolls(
|
||||||
@@ -88,45 +146,45 @@ public class PollController(AppDatabase db, PollService polls, PublisherService
|
|||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
var accountId = Guid.Parse(currentUser.Id);
|
var accountId = Guid.Parse(currentUser.Id);
|
||||||
|
|
||||||
// Start a transaction
|
// Start a transaction
|
||||||
await using var transaction = await db.Database.BeginTransactionAsync();
|
await using var transaction = await db.Database.BeginTransactionAsync();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var poll = await db.Polls
|
var poll = await db.Polls
|
||||||
.Include(p => p.Questions)
|
.Include(p => p.Questions)
|
||||||
.FirstOrDefaultAsync(p => p.Id == id);
|
.FirstOrDefaultAsync(p => p.Id == id);
|
||||||
|
|
||||||
if (poll == null) return NotFound("Poll not found");
|
if (poll == null) return NotFound("Poll not found");
|
||||||
|
|
||||||
// Check if user is an editor of the publisher that owns the poll
|
// Check if user is an editor of the publisher that owns the poll
|
||||||
if (!await pub.IsMemberWithRole(poll.PublisherId, accountId, PublisherMemberRole.Editor))
|
if (!await pub.IsMemberWithRole(poll.PublisherId, accountId, PublisherMemberRole.Editor))
|
||||||
return StatusCode(403, "You need to be at least an editor to update this poll.");
|
return StatusCode(403, "You need to be at least an editor to update this poll.");
|
||||||
|
|
||||||
// Update properties if they are provided in the request
|
// Update properties if they are provided in the request
|
||||||
if (request.Title != null) poll.Title = request.Title;
|
if (request.Title != null) poll.Title = request.Title;
|
||||||
if (request.Description != null) poll.Description = request.Description;
|
if (request.Description != null) poll.Description = request.Description;
|
||||||
if (request.EndedAt.HasValue) poll.EndedAt = request.EndedAt;
|
if (request.EndedAt.HasValue) poll.EndedAt = request.EndedAt;
|
||||||
|
|
||||||
// Update questions if provided
|
// Update questions if provided
|
||||||
if (request.Questions != null)
|
if (request.Questions != null)
|
||||||
{
|
{
|
||||||
// Remove existing questions
|
// Remove existing questions
|
||||||
db.PollQuestions.RemoveRange(poll.Questions);
|
db.PollQuestions.RemoveRange(poll.Questions);
|
||||||
|
|
||||||
// Add new questions
|
// Add new questions
|
||||||
poll.Questions = request.Questions;
|
poll.Questions = request.Questions;
|
||||||
}
|
}
|
||||||
|
|
||||||
polls.ValidatePoll(poll);
|
polls.ValidatePoll(poll);
|
||||||
|
|
||||||
poll.UpdatedAt = SystemClock.Instance.GetCurrentInstant();
|
poll.UpdatedAt = SystemClock.Instance.GetCurrentInstant();
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
// Commit the transaction if all operations succeed
|
// Commit the transaction if all operations succeed
|
||||||
await transaction.CommitAsync();
|
await transaction.CommitAsync();
|
||||||
|
|
||||||
return Ok(poll);
|
return Ok(poll);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -142,42 +200,42 @@ public class PollController(AppDatabase db, PollService polls, PublisherService
|
|||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
var accountId = Guid.Parse(currentUser.Id);
|
var accountId = Guid.Parse(currentUser.Id);
|
||||||
|
|
||||||
// Start a transaction
|
// Start a transaction
|
||||||
await using var transaction = await db.Database.BeginTransactionAsync();
|
await using var transaction = await db.Database.BeginTransactionAsync();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var poll = await db.Polls
|
var poll = await db.Polls
|
||||||
.Include(p => p.Questions)
|
.Include(p => p.Questions)
|
||||||
.FirstOrDefaultAsync(p => p.Id == id);
|
.FirstOrDefaultAsync(p => p.Id == id);
|
||||||
|
|
||||||
if (poll == null) return NotFound("Poll not found");
|
if (poll == null) return NotFound("Poll not found");
|
||||||
|
|
||||||
// Check if user is an editor of the publisher that owns the poll
|
// Check if user is an editor of the publisher that owns the poll
|
||||||
if (!await pub.IsMemberWithRole(poll.PublisherId, accountId, PublisherMemberRole.Editor))
|
if (!await pub.IsMemberWithRole(poll.PublisherId, accountId, PublisherMemberRole.Editor))
|
||||||
return StatusCode(403, "You need to be at least an editor to delete this poll.");
|
return StatusCode(403, "You need to be at least an editor to delete this poll.");
|
||||||
|
|
||||||
// Delete all answers for this poll
|
// Delete all answers for this poll
|
||||||
var answers = await db.PollAnswers
|
var answers = await db.PollAnswers
|
||||||
.Where(a => a.PollId == id)
|
.Where(a => a.PollId == id)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
if (answers.Count != 0)
|
if (answers.Count != 0)
|
||||||
db.PollAnswers.RemoveRange(answers);
|
db.PollAnswers.RemoveRange(answers);
|
||||||
|
|
||||||
// Delete all questions for this poll
|
// Delete all questions for this poll
|
||||||
if (poll.Questions.Count != 0)
|
if (poll.Questions.Count != 0)
|
||||||
db.PollQuestions.RemoveRange(poll.Questions);
|
db.PollQuestions.RemoveRange(poll.Questions);
|
||||||
|
|
||||||
// Finally, delete the poll itself
|
// Finally, delete the poll itself
|
||||||
db.Polls.Remove(poll);
|
db.Polls.Remove(poll);
|
||||||
|
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
// Commit the transaction if all operations succeed
|
// Commit the transaction if all operations succeed
|
||||||
await transaction.CommitAsync();
|
await transaction.CommitAsync();
|
||||||
|
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
Reference in New Issue
Block a user