♻️ Centralized data models (wip)
This commit is contained in:
@@ -1,67 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using DysonNetwork.Shared.Data;
|
||||
using NodaTime;
|
||||
|
||||
namespace DysonNetwork.Sphere.Poll;
|
||||
|
||||
public class Poll : ModelBase
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
public List<PollQuestion> Questions { get; set; } = new();
|
||||
|
||||
[MaxLength(1024)] public string? Title { get; set; }
|
||||
[MaxLength(4096)] public string? Description { get; set; }
|
||||
|
||||
public Instant? EndedAt { get; set; }
|
||||
public bool IsAnonymous { get; set; }
|
||||
|
||||
public Guid PublisherId { get; set; }
|
||||
[JsonIgnore] public Publisher.Publisher? Publisher { get; set; }
|
||||
}
|
||||
|
||||
public enum PollQuestionType
|
||||
{
|
||||
SingleChoice,
|
||||
MultipleChoice,
|
||||
YesNo,
|
||||
Rating,
|
||||
FreeText
|
||||
}
|
||||
|
||||
public class PollQuestion : ModelBase
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
public PollQuestionType Type { get; set; }
|
||||
[Column(TypeName = "jsonb")] public List<PollOption>? Options { get; set; }
|
||||
|
||||
[MaxLength(1024)] public string Title { get; set; } = null!;
|
||||
[MaxLength(4096)] public string? Description { get; set; }
|
||||
public int Order { get; set; } = 0;
|
||||
public bool IsRequired { get; set; }
|
||||
|
||||
public Guid PollId { get; set; }
|
||||
[JsonIgnore] public Poll Poll { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class PollOption
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
[Required][MaxLength(1024)] public string Label { get; set; } = null!;
|
||||
[MaxLength(4096)] public string? Description { get; set; }
|
||||
public int Order { get; set; } = 0;
|
||||
}
|
||||
|
||||
public class PollAnswer : ModelBase
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
[Column(TypeName = "jsonb")] public Dictionary<string, JsonElement> Answer { get; set; } = null!;
|
||||
|
||||
public Guid AccountId { get; set; }
|
||||
public Guid PollId { get; set; }
|
||||
[JsonIgnore] public Poll? Poll { get; set; }
|
||||
[NotMapped] public AccountReference? Account { get; set; }
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Shared.Data;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Shared.Proto;
|
||||
using DysonNetwork.Shared.Registry;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
@@ -46,7 +47,7 @@ public class PollController(
|
||||
|
||||
[HttpPost("{id:guid}/answer")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<PollAnswer>> AnswerPoll(Guid id, [FromBody] PollAnswerRequest request)
|
||||
public async Task<ActionResult<SnPollAnswer>> AnswerPoll(Guid id, [FromBody] PollAnswerRequest request)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
var accountId = Guid.Parse(currentUser.Id);
|
||||
@@ -78,7 +79,7 @@ public class PollController(
|
||||
}
|
||||
|
||||
[HttpGet("{id:guid}/feedback")]
|
||||
public async Task<ActionResult<List<PollAnswer>>> GetPollFeedback(
|
||||
public async Task<ActionResult<List<SnPollAnswer>>> GetPollFeedback(
|
||||
Guid id,
|
||||
[FromQuery] int offset = 0,
|
||||
[FromQuery] int take = 20
|
||||
@@ -91,7 +92,7 @@ public class PollController(
|
||||
.FirstOrDefaultAsync(p => p.Id == id);
|
||||
if (poll is null) return NotFound("Poll not found");
|
||||
|
||||
if (!await pub.IsMemberWithRole(poll.PublisherId, accountId, Publisher.PublisherMemberRole.Viewer))
|
||||
if (!await pub.IsMemberWithRole(poll.PublisherId, accountId, Shared.Models.PublisherMemberRole.Viewer))
|
||||
return StatusCode(403, "You need to be a viewer to view this poll's feedback.");
|
||||
|
||||
var answerQuery = db.PollAnswers
|
||||
@@ -117,7 +118,7 @@ public class PollController(
|
||||
{
|
||||
var protoValue = answeredAccounts.FirstOrDefault(a => a.Id == answer.AccountId.ToString());
|
||||
if (protoValue is not null)
|
||||
answer.Account = AccountReference.FromProtoValue(protoValue);
|
||||
answer.Account = SnAccount.FromProtoValue(protoValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,14 +178,14 @@ public class PollController(
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
public PollQuestionType Type { get; set; }
|
||||
public List<PollOption>? Options { get; set; }
|
||||
public List<SnPollOption>? Options { get; set; }
|
||||
|
||||
[MaxLength(1024)] public string Title { get; set; } = null!;
|
||||
[MaxLength(4096)] public string? Description { get; set; }
|
||||
public int Order { get; set; } = 0;
|
||||
public bool IsRequired { get; set; }
|
||||
|
||||
public PollQuestion ToQuestion() => new()
|
||||
public SnPollQuestion ToQuestion() => new()
|
||||
{
|
||||
Id = Id,
|
||||
Type = Type,
|
||||
@@ -207,7 +208,7 @@ public class PollController(
|
||||
|
||||
var publisher = await pub.GetPublisherByName(pubName);
|
||||
if (publisher is null) return BadRequest("Publisher was not found.");
|
||||
if (!await pub.IsMemberWithRole(publisher.Id, accountId, Publisher.PublisherMemberRole.Editor))
|
||||
if (!await pub.IsMemberWithRole(publisher.Id, accountId, Shared.Models.PublisherMemberRole.Editor))
|
||||
return StatusCode(403, "You need at least be an editor to create polls as this publisher.");
|
||||
|
||||
var poll = new Poll
|
||||
@@ -253,7 +254,7 @@ public class PollController(
|
||||
if (poll == null) return NotFound("Poll not found");
|
||||
|
||||
// Check if user is an editor of the publisher that owns the poll
|
||||
if (!await pub.IsMemberWithRole(poll.PublisherId, accountId, Publisher.PublisherMemberRole.Editor))
|
||||
if (!await pub.IsMemberWithRole(poll.PublisherId, accountId, Shared.Models.PublisherMemberRole.Editor))
|
||||
return StatusCode(403, "You need to be at least an editor to update this poll.");
|
||||
|
||||
// Update properties if they are provided in the request
|
||||
@@ -317,7 +318,7 @@ public class PollController(
|
||||
if (poll == null) return NotFound("Poll not found");
|
||||
|
||||
// Check if user is an editor of the publisher that owns the poll
|
||||
if (!await pub.IsMemberWithRole(poll.PublisherId, accountId, Publisher.PublisherMemberRole.Editor))
|
||||
if (!await pub.IsMemberWithRole(poll.PublisherId, accountId, Shared.Models.PublisherMemberRole.Editor))
|
||||
return StatusCode(403, "You need to be at least an editor to delete this poll.");
|
||||
|
||||
// Delete all answers for this poll
|
||||
|
@@ -1,13 +1,14 @@
|
||||
using DysonNetwork.Shared.Models;
|
||||
using DysonNetwork.Sphere.WebReader;
|
||||
|
||||
namespace DysonNetwork.Sphere.Poll;
|
||||
|
||||
public class PollWithStats : Poll
|
||||
{
|
||||
public PollAnswer? UserAnswer { get; set; }
|
||||
public SnPollAnswer? UserAnswer { get; set; }
|
||||
public Dictionary<Guid, Dictionary<string, int>> Stats { get; set; } = new(); // question id -> (option id -> count)
|
||||
|
||||
public static PollWithStats FromPoll(Poll poll, PollAnswer? userAnswer = null)
|
||||
public static PollWithStats FromPoll(Poll poll, SnPollAnswer? userAnswer = null)
|
||||
{
|
||||
return new PollWithStats
|
||||
{
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Shared.Cache;
|
||||
using DysonNetwork.Shared.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NodaTime;
|
||||
|
||||
@@ -42,10 +43,10 @@ public class PollService(AppDatabase db, ICacheService cache)
|
||||
|
||||
private const string PollAnswerCachePrefix = "poll:answer:";
|
||||
|
||||
public async Task<PollAnswer?> GetPollAnswer(Guid pollId, Guid accountId)
|
||||
public async Task<SnPollAnswer?> GetPollAnswer(Guid pollId, Guid accountId)
|
||||
{
|
||||
var cacheKey = $"{PollAnswerCachePrefix}{pollId}:{accountId}";
|
||||
var cachedAnswer = await cache.GetAsync<PollAnswer?>(cacheKey);
|
||||
var cachedAnswer = await cache.GetAsync<SnPollAnswer?>(cacheKey);
|
||||
if (cachedAnswer is not null)
|
||||
return cachedAnswer;
|
||||
|
||||
@@ -103,7 +104,7 @@ public class PollService(AppDatabase db, ICacheService cache)
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<PollAnswer> AnswerPoll(Guid pollId, Guid accountId, Dictionary<string, JsonElement> answer)
|
||||
public async Task<SnPollAnswer> AnswerPoll(Guid pollId, Guid accountId, Dictionary<string, JsonElement> answer)
|
||||
{
|
||||
// Validation
|
||||
var poll = await db.Polls
|
||||
@@ -124,7 +125,7 @@ public class PollService(AppDatabase db, ICacheService cache)
|
||||
await UnAnswerPoll(pollId, accountId);
|
||||
|
||||
// Save the new answer
|
||||
var answerRecord = new PollAnswer
|
||||
var answerRecord = new SnPollAnswer
|
||||
{
|
||||
PollId = pollId,
|
||||
AccountId = accountId,
|
||||
|
Reference in New Issue
Block a user