the files
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
using LiteDB;
|
||||
|
||||
namespace Campus_live_rewrite.api.dbs
|
||||
{
|
||||
/// <summary>
|
||||
/// Website support tickets. A signed-in player opens a ticket (from the Support page bot's
|
||||
/// "talk to a real person" flow); staff (dev / mod / owner) see EVERY ticket and can reply,
|
||||
/// close and reopen. Stored in its own LiteDB file; checkpointed by DbMaintenance.
|
||||
/// </summary>
|
||||
public static class SupportDB
|
||||
{
|
||||
private static readonly LiteDatabase DB =
|
||||
new LiteDatabase(Environment.CurrentDirectory + "/Data/DBs/Support.db");
|
||||
|
||||
public static void Checkpoint() => DB.Checkpoint();
|
||||
|
||||
private static ILiteCollection<Ticket> Tickets => DB.GetCollection<Ticket>("tickets");
|
||||
|
||||
static SupportDB()
|
||||
{
|
||||
Tickets.EnsureIndex(x => x.AccountId);
|
||||
Tickets.EnsureIndex(x => x.Status);
|
||||
}
|
||||
|
||||
public sealed class TicketMessage
|
||||
{
|
||||
public ulong FromAccountId { get; set; }
|
||||
public string FromName { get; set; } = "";
|
||||
public bool Staff { get; set; }
|
||||
public string Body { get; set; } = "";
|
||||
public DateTime At { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public sealed class Ticket
|
||||
{
|
||||
public int Id { get; set; } // LiteDB auto-increment PK
|
||||
public ulong AccountId { get; set; }
|
||||
public string Username { get; set; } = "";
|
||||
public string Subject { get; set; } = "";
|
||||
public string Status { get; set; } = "open"; // "open" | "closed"
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
public List<TicketMessage> Messages { get; set; } = new();
|
||||
}
|
||||
|
||||
public static Ticket Create(ulong accountId, string username, string subject, string body)
|
||||
{
|
||||
var t = new Ticket
|
||||
{
|
||||
AccountId = accountId,
|
||||
Username = username,
|
||||
Subject = string.IsNullOrWhiteSpace(subject) ? "Support request" : subject,
|
||||
Status = "open",
|
||||
};
|
||||
t.Messages.Add(new TicketMessage { FromAccountId = accountId, FromName = username, Staff = false, Body = body });
|
||||
Tickets.Insert(t); // Id auto-assigned
|
||||
return t;
|
||||
}
|
||||
|
||||
public static Ticket? Get(int id) => Tickets.FindById(id);
|
||||
|
||||
public static List<Ticket> ForAccount(ulong accountId) =>
|
||||
Tickets.Find(x => x.AccountId == accountId).OrderByDescending(x => x.UpdatedAt).ToList();
|
||||
|
||||
public static List<Ticket> All(string? status)
|
||||
{
|
||||
var rows = status == "open" ? Tickets.Find(x => x.Status == "open")
|
||||
: status == "closed" ? Tickets.Find(x => x.Status == "closed")
|
||||
: Tickets.FindAll();
|
||||
return rows.OrderByDescending(x => x.UpdatedAt).ToList();
|
||||
}
|
||||
|
||||
public static bool AddMessage(int id, ulong fromId, string fromName, bool staff, string body)
|
||||
{
|
||||
var t = Tickets.FindById(id);
|
||||
if (t == null) return false;
|
||||
t.Messages.Add(new TicketMessage { FromAccountId = fromId, FromName = fromName, Staff = staff, Body = body });
|
||||
t.UpdatedAt = DateTime.UtcNow;
|
||||
// A reply on a closed ticket reopens it, so nobody's follow-up is lost in a closed thread.
|
||||
if (t.Status == "closed") t.Status = "open";
|
||||
Tickets.Update(t);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool SetStatus(int id, string status)
|
||||
{
|
||||
var t = Tickets.FindById(id);
|
||||
if (t == null) return false;
|
||||
t.Status = status;
|
||||
t.UpdatedAt = DateTime.UtcNow;
|
||||
Tickets.Update(t);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int OpenCount() => Tickets.Count(x => x.Status == "open");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user