the files
This commit is contained in:
@@ -0,0 +1,300 @@
|
||||
using Discord;
|
||||
using LiteDB;
|
||||
using Campus_live_rewrite.api.server.Classes.db_class;
|
||||
using static Campus_live_rewrite.api.server.Classes.db_class.EventDBClasses;
|
||||
|
||||
namespace Campus_live_rewrite.api.dbs
|
||||
{
|
||||
public class EventDB
|
||||
{
|
||||
public static LiteDatabase EventDBFile = new LiteDatabase(Environment.CurrentDirectory + "/Data/DBs/Events.db");
|
||||
private static ILiteCollection<FullPlayerEvent> Events => EventDBFile.GetCollection<FullPlayerEvent>("events");
|
||||
|
||||
private static ulong GetNextId()
|
||||
{
|
||||
var last = Events.Query()
|
||||
.OrderByDescending(x => x.PlayerEventId)
|
||||
.FirstOrDefault();
|
||||
|
||||
return last == null ? 1UL : last.PlayerEventId + 1;
|
||||
}
|
||||
|
||||
public static FullPlayerEvent? GetFullEventById(ulong eventId)
|
||||
{
|
||||
return Events.FindById(eventId);
|
||||
}
|
||||
|
||||
/// <summary>Apply an edit to a stored event and persist it. Null when the event is unknown.</summary>
|
||||
public static FullPlayerEvent? Mutate(ulong eventId, Action<FullPlayerEvent> edit)
|
||||
{
|
||||
var ev = Events.FindById(eventId);
|
||||
if (ev == null) return null;
|
||||
edit(ev);
|
||||
Events.Update(ev);
|
||||
return ev;
|
||||
}
|
||||
|
||||
public static FullPlayerEvent? SetEventName(ulong eventId, string NewName)
|
||||
{
|
||||
var ev = Events.FindById(eventId);
|
||||
if (ev == null)
|
||||
return null;
|
||||
|
||||
ev.Name = NewName;
|
||||
Events.Update(ev);
|
||||
|
||||
return ev;
|
||||
}
|
||||
|
||||
public static FullPlayerEvent? SetEventImageName(ulong eventId, string NewImageName)
|
||||
{
|
||||
var ev = Events.FindById(eventId);
|
||||
if (ev == null)
|
||||
return null;
|
||||
|
||||
ev.ImageName = NewImageName;
|
||||
Events.Update(ev);
|
||||
|
||||
return ev;
|
||||
}
|
||||
|
||||
public static FullPlayerEvent? SetEventDescription(ulong eventId, string newDescription)
|
||||
{
|
||||
var ev = Events.FindById(eventId);
|
||||
if (ev == null) return null;
|
||||
ev.Description = newDescription;
|
||||
Events.Update(ev);
|
||||
return ev;
|
||||
}
|
||||
|
||||
public static FullPlayerEvent? SetEventTime(ulong eventId, DateTime start, DateTime end)
|
||||
{
|
||||
var ev = Events.FindById(eventId);
|
||||
if (ev == null) return null;
|
||||
ev.StartTime = start;
|
||||
ev.EndTime = end;
|
||||
Events.Update(ev);
|
||||
return ev;
|
||||
}
|
||||
|
||||
public static FullPlayerEvent? SetEventAccessibility(ulong eventId, EventDBClasses.PlayerEventAccessibility accessibility)
|
||||
{
|
||||
var ev = Events.FindById(eventId);
|
||||
if (ev == null) return null;
|
||||
ev.Accessibility = accessibility;
|
||||
Events.Update(ev);
|
||||
return ev;
|
||||
}
|
||||
|
||||
public static FullPlayerEvent? SetEventTags(ulong eventId, List<string> tags)
|
||||
{
|
||||
var ev = Events.FindById(eventId);
|
||||
if (ev == null) return null;
|
||||
ev.Tags = (tags ?? new List<string>())
|
||||
.Where(t => !string.IsNullOrWhiteSpace(t))
|
||||
.Select(t => new EventDBClasses.FullTag { Tag = t.Trim(), Type = EventDBClasses.TagType.Unknown1 })
|
||||
.ToList();
|
||||
Events.Update(ev);
|
||||
return ev;
|
||||
}
|
||||
|
||||
public static List<FullPlayerEvent> SearchEventByQuery(string? query)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
{
|
||||
return Events.Query()
|
||||
.OrderBy(e => e.StartTime)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
query = query.Trim();
|
||||
|
||||
bool isTagSearch =
|
||||
query.StartsWith("#") ||
|
||||
query.StartsWith("%23");
|
||||
|
||||
if (isTagSearch)
|
||||
{
|
||||
string tag = query
|
||||
.Replace("%23", "")
|
||||
.TrimStart('#')
|
||||
.ToLower();
|
||||
|
||||
return Events
|
||||
.Find(Query.EQ("Tags.Tag", tag))
|
||||
.OrderBy(e => e.StartTime)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
string nameQuery = query.ToLower();
|
||||
|
||||
return Events.Query()
|
||||
.Where(e =>
|
||||
e.Name != null &&
|
||||
e.Name.ToLower().Contains(nameQuery))
|
||||
.OrderBy(e => e.StartTime)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Events scheduled in a given room. /api/playerevents/v1/room/{RoomId} used to answer
|
||||
/// a hardcoded "[]" (marked "todo db"), so a room never showed the events booked in it.
|
||||
/// </summary>
|
||||
public static List<FullPlayerEvent> GetEventsForRoom(ulong roomId)
|
||||
{
|
||||
return Events.Query()
|
||||
.Where(e => e.RoomId == roomId)
|
||||
.OrderBy(e => e.StartTime)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Events happening right now - started, not yet ended. /api/playerevents/v1/searchlive
|
||||
/// was another hardcoded "[]", so the "live now" list was always empty however many
|
||||
/// events were running.
|
||||
/// </summary>
|
||||
public static List<FullPlayerEvent> GetLiveEvents()
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
return Events.Query()
|
||||
.ToList()
|
||||
.Where(e => e.StartTime.ToUniversalTime() <= now && e.EndTime.ToUniversalTime() >= now)
|
||||
.OrderBy(e => e.StartTime)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Records a player's RSVP and keeps AttendeeCount in step with it. One response per
|
||||
/// player per event - responding again replaces the previous answer.
|
||||
/// </summary>
|
||||
public static FullPlayerEvent? SetResponse(ulong eventId, ulong playerId, PlayerEventResponseType type)
|
||||
{
|
||||
var ev = Events.FindById(eventId);
|
||||
if (ev == null) return null;
|
||||
|
||||
ev.Responses ??= new List<FullEventResponses>();
|
||||
ev.Responses.RemoveAll(r => r.PlayerId == playerId);
|
||||
|
||||
if (type != PlayerEventResponseType.None)
|
||||
{
|
||||
ulong nextId = ev.Responses.Count == 0 ? 1UL : ev.Responses.Max(r => r.PlayerEventResponseId) + 1;
|
||||
ev.Responses.Add(new FullEventResponses
|
||||
{
|
||||
PlayerEventResponseId = nextId,
|
||||
PlayerEventId = eventId,
|
||||
PlayerId = playerId,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
Type = type
|
||||
});
|
||||
}
|
||||
|
||||
// AttendeeCount was never maintained - it sat at 0 no matter how many people
|
||||
// responded, so every event advertised itself as empty.
|
||||
ev.AttendeeCount = ev.Responses.Count(r => r.Type == PlayerEventResponseType.Yes);
|
||||
Events.Update(ev);
|
||||
return ev;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether a player may enter an event's room, and why not when they may not.
|
||||
///
|
||||
/// Rules:
|
||||
/// - the CREATOR may join at any time, including before it starts (they have to be
|
||||
/// able to set the room up).
|
||||
/// - anyone INVITED may join at any time. An invite is a response row: the invite
|
||||
/// flow writes Pending, and Yes / Interested / No all mean the player is already
|
||||
/// part of the event, so any response row counts.
|
||||
/// - everyone else may only join once it has actually started, and not after it has
|
||||
/// ended.
|
||||
///
|
||||
/// Returns true when entry is allowed; `reason` explains a refusal for the log.
|
||||
/// </summary>
|
||||
public static bool CanPlayerJoin(FullPlayerEvent ev, ulong playerId, out string reason)
|
||||
{
|
||||
reason = "";
|
||||
|
||||
if (ev.CreatorPlayerId == playerId)
|
||||
return true;
|
||||
|
||||
bool invited = ev.Responses?.Any(r => r.PlayerId == playerId) == true;
|
||||
if (invited)
|
||||
return true;
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
// Doors open a few minutes early so people can be in the room when it starts.
|
||||
if (now < ev.StartTime.ToUniversalTime().AddMinutes(-Campus_live_rewrite.api.server.ConfigCampus.EventEarlyJoinMinutes))
|
||||
{
|
||||
reason = $"event has not started (starts {ev.StartTime:u}, not invited)";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (now > ev.EndTime.ToUniversalTime())
|
||||
{
|
||||
reason = $"event already ended ({ev.EndTime:u})";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>Marks an event live / not live. Used by roominstance/{id}/inprogress.</summary>
|
||||
public static FullPlayerEvent? SetBroadcastingInstance(ulong eventId, ulong roomInstanceId, bool inProgress)
|
||||
{
|
||||
var ev = Events.FindById(eventId);
|
||||
if (ev == null) return null;
|
||||
|
||||
ev.BroadcastingRoomInstanceId = inProgress ? roomInstanceId : 0;
|
||||
ev.State = inProgress ? 1 : 0;
|
||||
Events.Update(ev);
|
||||
return ev;
|
||||
}
|
||||
|
||||
/// <summary>The event currently broadcasting to a given room instance, if any.</summary>
|
||||
public static FullPlayerEvent? GetEventForRoomInstance(ulong roomInstanceId)
|
||||
{
|
||||
if (roomInstanceId == 0) return null;
|
||||
return Events.Query()
|
||||
.Where(e => e.BroadcastingRoomInstanceId == roomInstanceId)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>Removes an event outright. Used by the admin panel for moderation.</summary>
|
||||
public static bool DeleteEvent(ulong eventId) => Events.Delete(eventId);
|
||||
|
||||
public static FullPlayerEvent CreateEvent(ulong creatorPlayerId, EventDBClasses.CreateEventRequest request)
|
||||
{
|
||||
var ev = new FullPlayerEvent
|
||||
{
|
||||
PlayerEventId = GetNextId(),
|
||||
CreatorPlayerId = creatorPlayerId,
|
||||
RoomId = request.RoomId,
|
||||
SubRoomId = request.SubRoomId,
|
||||
ClubId = request.ClubId,
|
||||
Name = request.Name,
|
||||
Description = request.Description,
|
||||
ImageName = request.ImageName,
|
||||
Tags = request.Tags?.Select(t => new EventDBClasses.FullTag
|
||||
{
|
||||
Tag = t,
|
||||
Type = EventDBClasses.TagType.Unknown1
|
||||
}).ToList(),
|
||||
StartTime = request.StartTime,
|
||||
EndTime = request.EndTime,
|
||||
AttendeeCount = 0,
|
||||
State = 0,
|
||||
Accessibility = request.Accessibility,
|
||||
IsMultiInstance = request.IsMultiInstance,
|
||||
SupportMultiInstanceRoomChat = request.SupportMultiInstanceRoomChat,
|
||||
DefaultBroadcastPermissions = (EventDBClasses.BroadcastPermissionsEnum)request.DefaultBroadcastPermissions,
|
||||
CanRequestBroadcastPermissions = (EventDBClasses.BroadcastPermissionsEnum)request.CanRequestBroadcastPermissions,
|
||||
Responses = new List<EventDBClasses.FullEventResponses>()
|
||||
};
|
||||
|
||||
Events.Insert(ev);
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user