|
|
|
@@ -0,0 +1,1259 @@
|
|
|
|
|
using System.Text.Json;
|
|
|
|
|
using Microsoft.AspNetCore.Authorization;
|
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
|
using RadicadeServer.API.Notifications;
|
|
|
|
|
using RadicadeServer.Clubs;
|
|
|
|
|
using RadicadeServer.DB;
|
|
|
|
|
using RadicadeServer.Extensions;
|
|
|
|
|
using RadicadeServer.RecNet.Enums;
|
|
|
|
|
using RadicadeServer.RecNet.Events;
|
|
|
|
|
using RadicadeServer.RecNet.Enums.Messages;
|
|
|
|
|
using RadicadeServer.RecNet.Messages;
|
|
|
|
|
using RadicadeServer.RecNet.Responses;
|
|
|
|
|
using RadicadeServer.RecNet.Rooms;
|
|
|
|
|
using RadicadeServer.Utils;
|
|
|
|
|
using ReportCategory = RadicadeServer.RecNet.Enums.Moderation.ReportCategory;
|
|
|
|
|
|
|
|
|
|
namespace RadicadeServer.API.Events
|
|
|
|
|
{
|
|
|
|
|
[Route("api/playerevents")]
|
|
|
|
|
public class EventsAPI(RecDBContext db) : Controller
|
|
|
|
|
{
|
|
|
|
|
private const string DefaultEventImageName = "default";
|
|
|
|
|
|
|
|
|
|
private const int EventResultSuccess = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private const int EventResultBroadcastNotMultiInstance = 27;
|
|
|
|
|
|
|
|
|
|
private static List<PlayerEventTag> ParseEventTags(string? tagsJson)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return JsonSerializer.Deserialize<List<PlayerEventTag>>(tagsJson ?? "[]") ?? [];
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static PlayerEventTag[] ParsePostedEventTags(Dictionary<string, string> fields)
|
|
|
|
|
{
|
|
|
|
|
var raw = GetEventField(fields, "Tags", "tags");
|
|
|
|
|
if (string.IsNullOrWhiteSpace(raw)) return [];
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using var document = JsonDocument.Parse(raw);
|
|
|
|
|
if (document.RootElement.ValueKind != JsonValueKind.Array) return [];
|
|
|
|
|
return document.RootElement.EnumerateArray()
|
|
|
|
|
.Select(entry =>
|
|
|
|
|
{
|
|
|
|
|
if (entry.ValueKind == JsonValueKind.String)
|
|
|
|
|
return new PlayerEventTag { Tag = entry.GetString() ?? string.Empty };
|
|
|
|
|
if (entry.ValueKind != JsonValueKind.Object)
|
|
|
|
|
return new PlayerEventTag();
|
|
|
|
|
|
|
|
|
|
var tag = entry.TryGetProperty("Tag", out var tagValue) || entry.TryGetProperty("tag", out tagValue)
|
|
|
|
|
? tagValue.GetString() ?? string.Empty
|
|
|
|
|
: string.Empty;
|
|
|
|
|
var type = entry.TryGetProperty("Type", out var typeValue) || entry.TryGetProperty("type", out typeValue)
|
|
|
|
|
? typeValue
|
|
|
|
|
: default;
|
|
|
|
|
return new PlayerEventTag
|
|
|
|
|
{
|
|
|
|
|
Tag = tag,
|
|
|
|
|
Type = type.ValueKind == JsonValueKind.Number && type.TryGetInt32(out var parsedType) ? parsedType : 0
|
|
|
|
|
};
|
|
|
|
|
})
|
|
|
|
|
.Where(tag => !string.IsNullOrWhiteSpace(tag.Tag))
|
|
|
|
|
.ToArray();
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static PlayerEvent ToPlayerEvent(PlayerEventDB ev)
|
|
|
|
|
{
|
|
|
|
|
return new PlayerEvent
|
|
|
|
|
{
|
|
|
|
|
PlayerEventId = ev.PlayerEventId,
|
|
|
|
|
Name = ev.Name,
|
|
|
|
|
Description = ev.Description,
|
|
|
|
|
ImageName = string.IsNullOrWhiteSpace(ev.ImageName) ? DefaultEventImageName : ev.ImageName,
|
|
|
|
|
StartTime = ev.StartTime,
|
|
|
|
|
EndTime = ev.EndTime,
|
|
|
|
|
CreatorPlayerId = ev.CreatorPlayerId,
|
|
|
|
|
AttendeeCount = ev.AttendeeCount,
|
|
|
|
|
RoomId = ev.RoomId,
|
|
|
|
|
SubRoomId = ev.SubRoomId,
|
|
|
|
|
Accessibility = ev.Accessibility,
|
|
|
|
|
ClubId = ev.ClubId,
|
|
|
|
|
State = ev.ModerationState,
|
|
|
|
|
Tags = ParseEventTags(ev.TagsJson),
|
|
|
|
|
CreatedAt = ev.CreatedAt,
|
|
|
|
|
PlayerCount = ev.AttendeeCount,
|
|
|
|
|
IsFull = false,
|
|
|
|
|
IsMultiInstance = ev.IsMultiInstance,
|
|
|
|
|
SupportMultiInstanceRoomChat = ev.SupportMultiInstanceRoomChat,
|
|
|
|
|
DefaultBroadcastPermissions = ev.DefaultBroadcastPermissions,
|
|
|
|
|
CanRequestBroadcastPermissions = ev.CanRequestBroadcastPermissions,
|
|
|
|
|
BroadcastingRoomInstanceId = ev.BroadcastingRoomInstanceId
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static EventResponse ToEventResponse(PlayerEventResponse r)
|
|
|
|
|
{
|
|
|
|
|
return new EventResponse
|
|
|
|
|
{
|
|
|
|
|
PlayerEventResponseId = r.PlayerEventResponseId,
|
|
|
|
|
PlayerEventId = r.PlayerEventId,
|
|
|
|
|
PlayerId = r.PlayerId,
|
|
|
|
|
CreatedAt = r.CreatedAt,
|
|
|
|
|
Type = r.Type
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static object ToEventEnvelope(PlayerEventDB ev)
|
|
|
|
|
{
|
|
|
|
|
var playerEvent = ToPlayerEvent(ev);
|
|
|
|
|
return new Dictionary<string, object?>
|
|
|
|
|
{
|
|
|
|
|
["PlayerEventId"] = playerEvent.PlayerEventId,
|
|
|
|
|
["Id"] = playerEvent.PlayerEventId,
|
|
|
|
|
["EventId"] = playerEvent.PlayerEventId,
|
|
|
|
|
["CreatorPlayerId"] = playerEvent.CreatorPlayerId,
|
|
|
|
|
["ImageName"] = playerEvent.ImageName,
|
|
|
|
|
["RoomId"] = playerEvent.RoomId,
|
|
|
|
|
["SubRoomId"] = playerEvent.SubRoomId,
|
|
|
|
|
["ClubId"] = playerEvent.ClubId,
|
|
|
|
|
["Name"] = playerEvent.Name,
|
|
|
|
|
["Description"] = playerEvent.Description,
|
|
|
|
|
["StartTime"] = EventClock.ToWire(playerEvent.StartTime),
|
|
|
|
|
["EndTime"] = EventClock.ToWire(playerEvent.EndTime),
|
|
|
|
|
["AttendeeCount"] = playerEvent.AttendeeCount,
|
|
|
|
|
["Accessibility"] = playerEvent.Accessibility,
|
|
|
|
|
["IsMultiInstance"] = playerEvent.IsMultiInstance,
|
|
|
|
|
["SupportMultiInstanceRoomChat"] = playerEvent.SupportMultiInstanceRoomChat,
|
|
|
|
|
["DefaultBroadcastPermissions"] = playerEvent.DefaultBroadcastPermissions,
|
|
|
|
|
["CanRequestBroadcastPermissions"] = playerEvent.CanRequestBroadcastPermissions,
|
|
|
|
|
["BroadcastingRoomInstanceId"] = playerEvent.BroadcastingRoomInstanceId,
|
|
|
|
|
["Tags"] = playerEvent.Tags.Select(tag => new Dictionary<string, object?>
|
|
|
|
|
{
|
|
|
|
|
["Tag"] = tag.Tag,
|
|
|
|
|
["Type"] = tag.Type
|
|
|
|
|
}).ToArray(),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static object ToEventResult(PlayerEventDB ev, int result = EventResultSuccess) => new
|
|
|
|
|
{
|
|
|
|
|
PlayerEvent = ToEventEnvelope(ev),
|
|
|
|
|
Result = result,
|
|
|
|
|
TagModifyResult = new { Result = result, Tags = Array.Empty<string>() }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1/searchlive"), Authorize]
|
|
|
|
|
[HttpGet("v1/search"), Authorize]
|
|
|
|
|
[HttpGet("v2/search"), Authorize]
|
|
|
|
|
public async Task<List<PlayerEvent>> SearchEvents([FromQuery] string? search = null, [FromQuery] string? query = null)
|
|
|
|
|
{
|
|
|
|
|
var events = await db.PlayerEvents.ToListAsync();
|
|
|
|
|
var results = PlayerEventQueries.Search(events, search ?? query, DateTime.UtcNow);
|
|
|
|
|
|
|
|
|
|
return results.Select(ToPlayerEvent).ToList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1"), Authorize]
|
|
|
|
|
public async Task<List<PlayerEvent>> GetBrowseFeed([FromQuery] int skip = 0, [FromQuery] int take = 50)
|
|
|
|
|
{
|
|
|
|
|
var now = DateTime.UtcNow;
|
|
|
|
|
var events = await db.PlayerEvents
|
|
|
|
|
.Where(x => x.EndTime > now)
|
|
|
|
|
.OrderBy(x => x.StartTime)
|
|
|
|
|
.Skip(Math.Max(0, skip))
|
|
|
|
|
.Take(Math.Clamp(take, 0, 100))
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
|
|
|
|
|
return events.Select(ToPlayerEvent).ToList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1/bulk"), Authorize]
|
|
|
|
|
public async Task<List<PlayerEvent>> GetEventsBulk([FromQuery] List<long>? id)
|
|
|
|
|
{
|
|
|
|
|
if (id == null || id.Count == 0) return [];
|
|
|
|
|
|
|
|
|
|
var events = await db.PlayerEvents
|
|
|
|
|
.Where(x => id.Contains(x.PlayerEventId))
|
|
|
|
|
.ToDictionaryAsync(x => x.PlayerEventId);
|
|
|
|
|
|
|
|
|
|
return id.Where(events.ContainsKey).Select(e => ToPlayerEvent(events[e])).ToList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1/creator/{playerId}"), Authorize]
|
|
|
|
|
public async Task<List<PlayerEvent>> GetEventsByCreator(long playerId)
|
|
|
|
|
{
|
|
|
|
|
var created = await db.PlayerEvents
|
|
|
|
|
.Where(x => x.CreatorPlayerId == playerId)
|
|
|
|
|
.OrderByDescending(x => x.StartTime)
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
|
|
|
|
|
return created.Select(ToPlayerEvent).ToList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1/tagfilters"), Authorize]
|
|
|
|
|
public RoomFilters GetEventTagFilters()
|
|
|
|
|
{
|
|
|
|
|
var pinned = new List<string>
|
|
|
|
|
{
|
|
|
|
|
"workshops", "celebration", "game", "meetup", "performance",
|
|
|
|
|
"coop", "grandopening", "class", "competition"
|
|
|
|
|
};
|
|
|
|
|
var popular = new List<string>
|
|
|
|
|
{
|
|
|
|
|
"workshops", "celebration", "class", "coop", "competition",
|
|
|
|
|
"game", "grandopening", "meetup", "performance"
|
|
|
|
|
};
|
|
|
|
|
return new RoomFilters
|
|
|
|
|
{
|
|
|
|
|
PinnedFilters = pinned,
|
|
|
|
|
PopularFilters = popular,
|
|
|
|
|
TrendingFilters = null
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1/all"), Authorize]
|
|
|
|
|
[HttpGet("v2/all"), Authorize]
|
|
|
|
|
[HttpGet("v2"), Authorize]
|
|
|
|
|
public async Task<AllEvents> GetAllEvents()
|
|
|
|
|
{
|
|
|
|
|
var userId = User.GetUserId() ?? 0;
|
|
|
|
|
|
|
|
|
|
var created = await db.PlayerEvents
|
|
|
|
|
.Where(x => x.CreatorPlayerId == userId)
|
|
|
|
|
.OrderByDescending(x => x.StartTime)
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
|
|
|
|
|
return new AllEvents
|
|
|
|
|
{
|
|
|
|
|
Created = created.Select(ToPlayerEvent).ToList(),
|
|
|
|
|
Responses = []
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1/all/{playerId:long}"), Authorize]
|
|
|
|
|
[HttpGet("v2/all/{playerId:long}"), Authorize]
|
|
|
|
|
public async Task<AllEvents> GetAllEventsForPlayer(long playerId)
|
|
|
|
|
{
|
|
|
|
|
var created = await db.PlayerEvents
|
|
|
|
|
.Where(x => x.CreatorPlayerId == playerId)
|
|
|
|
|
.OrderByDescending(x => x.StartTime)
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
|
|
|
|
|
return new AllEvents
|
|
|
|
|
{
|
|
|
|
|
Created = created.Select(ToPlayerEvent).ToList(),
|
|
|
|
|
Responses = []
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1/created"), Authorize]
|
|
|
|
|
[HttpGet("v2/created"), Authorize]
|
|
|
|
|
public async Task<List<PlayerEvent>> GetCreatedEvents()
|
|
|
|
|
{
|
|
|
|
|
var userId = User.GetUserId() ?? 0;
|
|
|
|
|
|
|
|
|
|
var created = await db.PlayerEvents
|
|
|
|
|
.Where(x => x.CreatorPlayerId == userId)
|
|
|
|
|
.OrderByDescending(x => x.StartTime)
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
|
|
|
|
|
return created.Select(ToPlayerEvent).ToList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1/room/{roomId}"), Authorize]
|
|
|
|
|
public async Task<List<PlayerEvent>> GetEventsInRoom(long roomId)
|
|
|
|
|
{
|
|
|
|
|
var events = await db.PlayerEvents.ToListAsync();
|
|
|
|
|
return PlayerEventQueries.InRoom(events, roomId).Select(ToPlayerEvent).ToList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1/clubs"), Authorize]
|
|
|
|
|
public async Task<List<PlayerEvent>> GetEventsByClubs([FromQuery] List<long>? id)
|
|
|
|
|
{
|
|
|
|
|
if (id == null || id.Count == 0) return [];
|
|
|
|
|
|
|
|
|
|
var events = await db.PlayerEvents
|
|
|
|
|
.Where(x => x.ClubId != null && id.Contains(x.ClubId.Value))
|
|
|
|
|
.OrderBy(x => x.StartTime)
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
return events.Select(ToPlayerEvent).ToList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1/club/{clubId:long}"), Authorize]
|
|
|
|
|
[HttpGet("v1/club_events/{clubId:long}"), Authorize]
|
|
|
|
|
public async Task<IActionResult> GetEventsByClub(long clubId)
|
|
|
|
|
{
|
|
|
|
|
var events = await db.PlayerEvents
|
|
|
|
|
.Where(x => x.ClubId == clubId)
|
|
|
|
|
.OrderBy(x => x.StartTime)
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
return Ok(new { Events = events.Select(ToPlayerEvent).ToList(), ContinuationToken = string.Empty });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1/events_by_club_ids/{clubIds}"), Authorize]
|
|
|
|
|
public IActionResult GetEventsByClubIdsLegacy(string clubIds)
|
|
|
|
|
{
|
|
|
|
|
return Ok(Array.Empty<object>());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1/remote_player_event_list/{accountId}"), Authorize]
|
|
|
|
|
public IActionResult GetRemotePlayerEventList(long accountId)
|
|
|
|
|
{
|
|
|
|
|
return Ok(new
|
|
|
|
|
{
|
|
|
|
|
Events = Array.Empty<object>(),
|
|
|
|
|
Responses = Array.Empty<object>()
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1/upcoming_events"), Authorize]
|
|
|
|
|
public async Task<List<PlayerEvent>> GetUpcomingEvents()
|
|
|
|
|
{
|
|
|
|
|
var events = await db.PlayerEvents
|
|
|
|
|
.Where(x => x.EndTime > DateTime.UtcNow)
|
|
|
|
|
.OrderBy(x => x.StartTime)
|
|
|
|
|
.Take(50)
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
return events.Select(ToPlayerEvent).ToList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1/filters"), Authorize]
|
|
|
|
|
public RoomFilters GetEventFilters() => GetEventTagFilters();
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1/{eventId:long}"), Authorize]
|
|
|
|
|
[HttpGet("v1/event/{eventId}"), Authorize]
|
|
|
|
|
public async Task<ActionResult<PlayerEvent>> GetEvent(long eventId)
|
|
|
|
|
{
|
|
|
|
|
var ev = await db.PlayerEvents.FirstOrDefaultAsync(x => x.PlayerEventId == eventId);
|
|
|
|
|
if (ev == null) return NotFound();
|
|
|
|
|
return Ok(ToPlayerEvent(ev));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet("v2/{eventId:long}"), Authorize]
|
|
|
|
|
public async Task<IActionResult> GetEventV2(long eventId)
|
|
|
|
|
{
|
|
|
|
|
var ev = await db.PlayerEvents.FirstOrDefaultAsync(x => x.PlayerEventId == eventId);
|
|
|
|
|
if (ev == null) return NotFound();
|
|
|
|
|
return Ok(ToEventResult(ev));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpPost("v1/create"), Authorize]
|
|
|
|
|
[HttpPost("v1/event"), Authorize]
|
|
|
|
|
[HttpPost("v1/event/create"), Authorize]
|
|
|
|
|
public async Task<ActionResult<PlayerEvent>> CreateEvent(
|
|
|
|
|
[FromForm] string name,
|
|
|
|
|
[FromForm] string? description,
|
|
|
|
|
[FromForm] long roomId,
|
|
|
|
|
[FromForm] DateTime? startTime,
|
|
|
|
|
[FromForm] DateTime? endTime,
|
|
|
|
|
[FromForm] string? imageName,
|
|
|
|
|
[FromForm] Accessibility? accessibility)
|
|
|
|
|
{
|
|
|
|
|
var userId = User.GetUserId();
|
|
|
|
|
if (userId == null) return Unauthorized();
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(name))
|
|
|
|
|
return BadRequest(new { error = "Event name is required." });
|
|
|
|
|
if (roomId <= 0)
|
|
|
|
|
return BadRequest(new { error = "A valid room id is required." });
|
|
|
|
|
|
|
|
|
|
var room = await db.Rooms.FirstOrDefaultAsync(x => x.RoomId == roomId);
|
|
|
|
|
if (room == null)
|
|
|
|
|
return BadRequest(new { error = "Room does not exist." });
|
|
|
|
|
|
|
|
|
|
var now = DateTime.UtcNow;
|
|
|
|
|
var ev = new PlayerEventDB
|
|
|
|
|
{
|
|
|
|
|
Name = name.Trim(),
|
|
|
|
|
Description = description ?? string.Empty,
|
|
|
|
|
ImageName = string.IsNullOrWhiteSpace(imageName) ? string.Empty : imageName,
|
|
|
|
|
StartTime = EventClock.FromPostedTime(startTime ?? now),
|
|
|
|
|
EndTime = EventClock.FromPostedTime(endTime ?? now.AddHours(2)),
|
|
|
|
|
CreatorPlayerId = userId.Value,
|
|
|
|
|
AttendeeCount = 1,
|
|
|
|
|
RoomId = roomId,
|
|
|
|
|
Accessibility = accessibility ?? Accessibility.Public,
|
|
|
|
|
CreatedAt = now
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
await db.PlayerEvents.AddAsync(ev);
|
|
|
|
|
await db.SaveChangesAsync();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
await db.PlayerEventResponses.AddAsync(new PlayerEventResponse
|
|
|
|
|
{
|
|
|
|
|
PlayerEventId = ev.PlayerEventId,
|
|
|
|
|
PlayerId = userId.Value,
|
|
|
|
|
Type = EventResponses.Yes
|
|
|
|
|
});
|
|
|
|
|
await db.SaveChangesAsync();
|
|
|
|
|
|
|
|
|
|
await PlayerEventNotifications.PushAsync(userId.Value, PlayerEventNotifications.Created(ev));
|
|
|
|
|
|
|
|
|
|
return Ok(ToPlayerEvent(ev));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpPost("v2"), Authorize]
|
|
|
|
|
public async Task<IActionResult> CreateEventV2()
|
|
|
|
|
{
|
|
|
|
|
var userId = User.GetUserId();
|
|
|
|
|
if (userId == null) return Unauthorized();
|
|
|
|
|
|
|
|
|
|
var fields = await ReadEventFieldsAsync();
|
|
|
|
|
|
|
|
|
|
var name = GetEventField(fields, "Name", "name");
|
|
|
|
|
var roomId = GetEventLong(fields, "RoomId", "roomId") ?? 0;
|
|
|
|
|
if (string.IsNullOrWhiteSpace(name) || roomId <= 0)
|
|
|
|
|
return BadRequest(new { error = "Invalid event request." });
|
|
|
|
|
|
|
|
|
|
var room = await db.Rooms.FirstOrDefaultAsync(x => x.RoomId == roomId);
|
|
|
|
|
if (room == null)
|
|
|
|
|
return BadRequest(new { error = "Room does not exist." });
|
|
|
|
|
|
|
|
|
|
var now = DateTime.UtcNow;
|
|
|
|
|
var ev = new PlayerEventDB
|
|
|
|
|
{
|
|
|
|
|
Name = name.Trim(),
|
|
|
|
|
Description = GetEventField(fields, "Description", "description") ?? string.Empty,
|
|
|
|
|
ImageName = GetEventField(fields, "ImageName", "imageName") ?? string.Empty,
|
|
|
|
|
StartTime = ParseEventDate(GetEventField(fields, "StartTime", "startTime"), now),
|
|
|
|
|
EndTime = ParseEventDate(GetEventField(fields, "EndTime", "endTime"), now.AddHours(2)),
|
|
|
|
|
CreatorPlayerId = userId.Value,
|
|
|
|
|
AttendeeCount = 0,
|
|
|
|
|
RoomId = roomId,
|
|
|
|
|
SubRoomId = GetEventLong(fields, "SubRoomId", "subRoomId"),
|
|
|
|
|
ClubId = GetEventLong(fields, "ClubId", "clubId"),
|
|
|
|
|
Accessibility = ParseEventAccessibility(GetEventField(fields, "Accessibility", "accessibility")),
|
|
|
|
|
IsMultiInstance = ParseEventBoolean(GetEventField(fields, "IsMultiInstance", "isMultiInstance")),
|
|
|
|
|
SupportMultiInstanceRoomChat = ParseEventBoolean(GetEventField(fields, "SupportMultiInstanceRoomChat", "supportMultiInstanceRoomChat")),
|
|
|
|
|
DefaultBroadcastPermissions = GetEventInt(fields, "DefaultBroadcastPermissions", "defaultBroadcastPermissions") ?? 0,
|
|
|
|
|
CanRequestBroadcastPermissions = GetEventInt(fields, "CanRequestBroadcastPermissions", "canRequestBroadcastPermissions") ?? 0,
|
|
|
|
|
TagsJson = JsonSerializer.Serialize(ParsePostedEventTags(fields)),
|
|
|
|
|
CreatedAt = now
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
await db.PlayerEvents.AddAsync(ev);
|
|
|
|
|
await db.SaveChangesAsync();
|
|
|
|
|
|
|
|
|
|
await db.PlayerEventResponses.AddAsync(new PlayerEventResponse
|
|
|
|
|
{
|
|
|
|
|
PlayerEventId = ev.PlayerEventId,
|
|
|
|
|
PlayerId = userId.Value,
|
|
|
|
|
Type = EventResponses.Yes
|
|
|
|
|
});
|
|
|
|
|
ev.AttendeeCount = 1;
|
|
|
|
|
await db.SaveChangesAsync();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
await PlayerEventNotifications.PushAsync(userId.Value, PlayerEventNotifications.Created(ev));
|
|
|
|
|
|
|
|
|
|
return Ok(ToEventResult(ev));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpPost("v2/{eventId:long}"), Authorize]
|
|
|
|
|
[HttpPut("v2/{eventId:long}/accessibility"), Authorize]
|
|
|
|
|
[HttpPut("v2/{eventId:long}/club"), Authorize]
|
|
|
|
|
[HttpPut("v2/{eventId:long}/description"), Authorize]
|
|
|
|
|
[HttpPut("v2/{eventId:long}/image"), Authorize]
|
|
|
|
|
[HttpPut("v2/{eventId:long}/multiinstance"), Authorize]
|
|
|
|
|
[HttpPut("v2/{eventId:long}/name"), Authorize]
|
|
|
|
|
[HttpPut("v2/{eventId:long}/room"), Authorize]
|
|
|
|
|
[HttpPut("v2/{eventId:long}/tags"), Authorize]
|
|
|
|
|
[HttpPut("v2/{eventId:long}/time"), Authorize]
|
|
|
|
|
public async Task<IActionResult> UpdateEventV2(long eventId)
|
|
|
|
|
{
|
|
|
|
|
var userId = User.GetUserId();
|
|
|
|
|
if (userId == null) return Unauthorized();
|
|
|
|
|
|
|
|
|
|
var ev = await db.PlayerEvents.FirstOrDefaultAsync(x => x.PlayerEventId == eventId);
|
|
|
|
|
if (ev == null) return NotFound();
|
|
|
|
|
if (ev.CreatorPlayerId != userId) return Forbid();
|
|
|
|
|
|
|
|
|
|
var fields = await ReadEventFieldsAsync();
|
|
|
|
|
|
|
|
|
|
var name = GetEventField(fields, "Name", "name");
|
|
|
|
|
if (name != null) ev.Name = name.Trim();
|
|
|
|
|
|
|
|
|
|
if (fields.TryGetValue("Description", out var description)) ev.Description = description;
|
|
|
|
|
|
|
|
|
|
if (fields.TryGetValue("ImageName", out var imageName)) ev.ImageName = imageName;
|
|
|
|
|
|
|
|
|
|
var startTime = GetEventField(fields, "StartTime", "startTime");
|
|
|
|
|
if (startTime != null) ev.StartTime = ParseEventDate(startTime, ev.StartTime);
|
|
|
|
|
|
|
|
|
|
var endTime = GetEventField(fields, "EndTime", "endTime");
|
|
|
|
|
if (endTime != null) ev.EndTime = ParseEventDate(endTime, ev.EndTime);
|
|
|
|
|
|
|
|
|
|
var roomId = GetEventLong(fields, "RoomId", "roomId");
|
|
|
|
|
if (roomId is > 0 && await db.Rooms.AnyAsync(x => x.RoomId == roomId)) ev.RoomId = roomId.Value;
|
|
|
|
|
|
|
|
|
|
if (fields.TryGetValue("SubRoomId", out var subRoomIdRaw) &&
|
|
|
|
|
TryParseNullableEventId(subRoomIdRaw, out var subRoomId))
|
|
|
|
|
ev.SubRoomId = subRoomId;
|
|
|
|
|
|
|
|
|
|
if (fields.TryGetValue("ClubId", out var clubIdRaw) &&
|
|
|
|
|
TryParseNullableEventId(clubIdRaw, out var clubId))
|
|
|
|
|
ev.ClubId = clubId;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var accessibility = GetEventField(fields, "Accessibility", "accessibility");
|
|
|
|
|
if (accessibility != null) ev.Accessibility = ParseEventAccessibility(accessibility);
|
|
|
|
|
|
|
|
|
|
var multiInstance = GetEventField(fields, "IsMultiInstance", "isMultiInstance");
|
|
|
|
|
if (multiInstance != null) ev.IsMultiInstance = ParseEventBoolean(multiInstance);
|
|
|
|
|
|
|
|
|
|
var roomChat = GetEventField(fields, "SupportMultiInstanceRoomChat", "supportMultiInstanceRoomChat");
|
|
|
|
|
if (roomChat != null) ev.SupportMultiInstanceRoomChat = ParseEventBoolean(roomChat);
|
|
|
|
|
|
|
|
|
|
var defaultBroadcastPermissions = GetEventInt(fields, "DefaultBroadcastPermissions", "defaultBroadcastPermissions");
|
|
|
|
|
if (defaultBroadcastPermissions != null) ev.DefaultBroadcastPermissions = defaultBroadcastPermissions.Value;
|
|
|
|
|
|
|
|
|
|
var canRequestBroadcastPermissions = GetEventInt(fields, "CanRequestBroadcastPermissions", "canRequestBroadcastPermissions");
|
|
|
|
|
if (canRequestBroadcastPermissions != null) ev.CanRequestBroadcastPermissions = canRequestBroadcastPermissions.Value;
|
|
|
|
|
|
|
|
|
|
if (fields.ContainsKey("Tags"))
|
|
|
|
|
ev.TagsJson = JsonSerializer.Serialize(ParsePostedEventTags(fields));
|
|
|
|
|
|
|
|
|
|
var updatePath = Request?.Path.Value?.TrimEnd('/').Split('/').LastOrDefault()?.ToLowerInvariant();
|
|
|
|
|
switch (updatePath)
|
|
|
|
|
{
|
|
|
|
|
case "accessibility":
|
|
|
|
|
if (GetEventField(fields, "Accessibility", "accessibility") is { } accessibilityValue)
|
|
|
|
|
ev.Accessibility = ParseEventAccessibility(accessibilityValue);
|
|
|
|
|
break;
|
|
|
|
|
case "club":
|
|
|
|
|
if (fields.TryGetValue("ClubId", out var clubValue) && TryParseNullableEventId(clubValue, out var parsedClubId))
|
|
|
|
|
ev.ClubId = parsedClubId;
|
|
|
|
|
break;
|
|
|
|
|
case "description":
|
|
|
|
|
if (fields.TryGetValue("Description", out var descriptionValue)) ev.Description = descriptionValue;
|
|
|
|
|
break;
|
|
|
|
|
case "image":
|
|
|
|
|
if (fields.TryGetValue("ImageName", out var imageValue)) ev.ImageName = imageValue;
|
|
|
|
|
break;
|
|
|
|
|
case "multiinstance":
|
|
|
|
|
if (GetEventField(fields, "IsMultiInstance", "isMultiInstance") is { } multiInstanceValue)
|
|
|
|
|
ev.IsMultiInstance = ParseEventBoolean(multiInstanceValue);
|
|
|
|
|
if (GetEventField(fields, "SupportMultiInstanceRoomChat", "supportMultiInstanceRoomChat") is { } multiChatValue)
|
|
|
|
|
ev.SupportMultiInstanceRoomChat = ParseEventBoolean(multiChatValue);
|
|
|
|
|
if (GetEventInt(fields, "DefaultBroadcastPermissions", "defaultBroadcastPermissions") is { } defaultPermissions)
|
|
|
|
|
ev.DefaultBroadcastPermissions = defaultPermissions;
|
|
|
|
|
if (GetEventInt(fields, "CanRequestBroadcastPermissions", "canRequestBroadcastPermissions") is { } requestPermissions)
|
|
|
|
|
ev.CanRequestBroadcastPermissions = requestPermissions;
|
|
|
|
|
break;
|
|
|
|
|
case "name":
|
|
|
|
|
if (fields.TryGetValue("Name", out var eventName)) ev.Name = eventName.Trim();
|
|
|
|
|
break;
|
|
|
|
|
case "room":
|
|
|
|
|
var updatedRoomId = GetEventLong(fields, "RoomId", "roomId");
|
|
|
|
|
if (updatedRoomId is > 0 &&
|
|
|
|
|
await db.Rooms.AnyAsync(x => x.RoomId == updatedRoomId.Value))
|
|
|
|
|
ev.RoomId = updatedRoomId.Value;
|
|
|
|
|
if (fields.TryGetValue("SubRoomId", out var subRoomValue) && TryParseNullableEventId(subRoomValue, out var parsedSubRoomId))
|
|
|
|
|
ev.SubRoomId = parsedSubRoomId;
|
|
|
|
|
break;
|
|
|
|
|
case "tags":
|
|
|
|
|
if (GetEventField(fields, "Tags", "tags") != null)
|
|
|
|
|
ev.TagsJson = JsonSerializer.Serialize(ParsePostedEventTags(fields));
|
|
|
|
|
break;
|
|
|
|
|
case "time":
|
|
|
|
|
if (GetEventField(fields, "StartTime", "startTime") is { } startValue)
|
|
|
|
|
ev.StartTime = ParseEventDate(startValue, ev.StartTime);
|
|
|
|
|
if (GetEventField(fields, "EndTime", "endTime") is { } endValue)
|
|
|
|
|
ev.EndTime = ParseEventDate(endValue, ev.EndTime);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await db.SaveChangesAsync();
|
|
|
|
|
|
|
|
|
|
await PlayerEventNotifications.PushAsync(ev.CreatorPlayerId, PlayerEventNotifications.Updated(ev));
|
|
|
|
|
|
|
|
|
|
return Ok(ToEventResult(ev));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpPost("v1/respond"), Authorize]
|
|
|
|
|
public async Task<IActionResult> RespondToEvent()
|
|
|
|
|
{
|
|
|
|
|
var userId = User.GetUserId();
|
|
|
|
|
if (userId == null) return Unauthorized();
|
|
|
|
|
|
|
|
|
|
var body = await ReadJsonBodyAsync();
|
|
|
|
|
if (body == null) return BadRequest();
|
|
|
|
|
|
|
|
|
|
var eventId = GetBodyLong(body.Value, "PlayerEventId", "playerEventId");
|
|
|
|
|
var typeRaw = GetBodyLong(body.Value, "Type", "type");
|
|
|
|
|
if (eventId == null || typeRaw == null) return BadRequest();
|
|
|
|
|
|
|
|
|
|
if (!Enum.IsDefined(typeof(EventResponses), (int)typeRaw.Value) ||
|
|
|
|
|
(EventResponses)(int)typeRaw.Value is EventResponses.None or EventResponses.Pending)
|
|
|
|
|
return BadRequest();
|
|
|
|
|
|
|
|
|
|
var response = await SetEventResponse((long)eventId, userId.Value, (EventResponses)(int)typeRaw.Value);
|
|
|
|
|
if (response == null) return NotFound();
|
|
|
|
|
|
|
|
|
|
return Ok(ToEventResult(response.Value.ev));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpPost("v1/event/{eventId}/response"), Authorize]
|
|
|
|
|
public async Task<ActionResult<EventResponse>> SetResponse(long eventId, [FromForm] EventResponses response)
|
|
|
|
|
{
|
|
|
|
|
var userId = User.GetUserId();
|
|
|
|
|
if (userId == null) return Unauthorized();
|
|
|
|
|
|
|
|
|
|
if (!Enum.IsDefined(typeof(EventResponses), response) || response is EventResponses.None or EventResponses.Pending)
|
|
|
|
|
return BadRequest();
|
|
|
|
|
|
|
|
|
|
var result = await SetEventResponse(eventId, userId.Value, response);
|
|
|
|
|
if (result == null) return NotFound();
|
|
|
|
|
|
|
|
|
|
return Ok(ToEventResponse(result.Value.response));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<(PlayerEventResponse response, PlayerEventDB ev)?> SetEventResponse(
|
|
|
|
|
long eventId, long playerId, EventResponses type)
|
|
|
|
|
{
|
|
|
|
|
var ev = await db.PlayerEvents.FirstOrDefaultAsync(x => x.PlayerEventId == eventId);
|
|
|
|
|
if (ev == null) return null;
|
|
|
|
|
|
|
|
|
|
var existing = await db.PlayerEventResponses
|
|
|
|
|
.FirstOrDefaultAsync(x => x.PlayerEventId == eventId && x.PlayerId == playerId);
|
|
|
|
|
|
|
|
|
|
var hasInvitation = existing?.Type == EventResponses.Pending ||
|
|
|
|
|
await db.Messages.AsNoTracking().AnyAsync(message =>
|
|
|
|
|
message.ToPlayerId == playerId &&
|
|
|
|
|
message.PlayerEventId == eventId &&
|
|
|
|
|
message.Type == MessageType.PlayerEventInvitation);
|
|
|
|
|
if (ev.Accessibility == Accessibility.Private &&
|
|
|
|
|
ev.CreatorPlayerId != playerId &&
|
|
|
|
|
!hasInvitation)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
if (existing == null)
|
|
|
|
|
{
|
|
|
|
|
existing = new PlayerEventResponse
|
|
|
|
|
{
|
|
|
|
|
PlayerEventId = eventId,
|
|
|
|
|
PlayerId = playerId,
|
|
|
|
|
Type = type
|
|
|
|
|
};
|
|
|
|
|
await db.PlayerEventResponses.AddAsync(existing);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
existing.Type = type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await db.SaveChangesAsync();
|
|
|
|
|
|
|
|
|
|
ev.AttendeeCount = await db.PlayerEventResponses
|
|
|
|
|
.CountAsync(x => x.PlayerEventId == eventId && x.Type == EventResponses.Yes);
|
|
|
|
|
|
|
|
|
|
await db.SaveChangesAsync();
|
|
|
|
|
return (existing, ev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpPost("v2/rsvp/{eventId:long}"), Authorize]
|
|
|
|
|
public async Task<ActionResult<EventResponse>> RespondToEventV2(long eventId)
|
|
|
|
|
{
|
|
|
|
|
var userId = User.GetUserId();
|
|
|
|
|
if (userId == null) return Unauthorized();
|
|
|
|
|
|
|
|
|
|
var result = await SetEventResponse(eventId, userId.Value, EventResponses.Yes);
|
|
|
|
|
if (result == null) return NotFound();
|
|
|
|
|
|
|
|
|
|
return Ok(ToEventResponse(result.Value.response));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpPost("v1/broadcast"), Authorize]
|
|
|
|
|
[HttpPut("v1/broadcast"), Authorize]
|
|
|
|
|
public async Task<IActionResult> BroadcastRoomInstance()
|
|
|
|
|
{
|
|
|
|
|
var userId = User.GetUserId();
|
|
|
|
|
if (userId == null) return Unauthorized();
|
|
|
|
|
|
|
|
|
|
var fields = await ReadEventFieldsAsync();
|
|
|
|
|
var eventId = GetEventLong(fields, "PlayerEventId", "playerEventId", "EventId", "eventId", "Id", "id") ?? 0;
|
|
|
|
|
if (eventId <= 0) eventId = await ReadEventIdFromRequestAsync();
|
|
|
|
|
if (eventId <= 0) return BadRequest(new { error = "PlayerEventId is required." });
|
|
|
|
|
|
|
|
|
|
var ev = await db.PlayerEvents.FirstOrDefaultAsync(x => x.PlayerEventId == eventId);
|
|
|
|
|
if (ev == null) return NotFound();
|
|
|
|
|
|
|
|
|
|
if (ev.CreatorPlayerId != userId && !await db.IsDeveloper(userId.Value))
|
|
|
|
|
return Forbid();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
long? roomInstanceId = null;
|
|
|
|
|
var rawInstance = GetEventField(fields,
|
|
|
|
|
"RoomInstanceId", "roomInstanceId", "BroadcastingRoomInstanceId", "broadcastingRoomInstanceId",
|
|
|
|
|
"BroadcastRoomInstanceId", "broadcastRoomInstanceId");
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(rawInstance) &&
|
|
|
|
|
!string.Equals(rawInstance, "null", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
if (!long.TryParse(rawInstance, out var parsedInstance) || parsedInstance <= 0)
|
|
|
|
|
return BadRequest(new { error = "RoomInstanceId must be a positive id or null." });
|
|
|
|
|
roomInstanceId = parsedInstance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (roomInstanceId.HasValue)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!ev.IsMultiInstance)
|
|
|
|
|
return Ok(ToEventResult(ev, EventResultBroadcastNotMultiInstance));
|
|
|
|
|
|
|
|
|
|
var instance = await db.RoomInstances
|
|
|
|
|
.FirstOrDefaultAsync(x => x.roomInstanceId == roomInstanceId.Value);
|
|
|
|
|
if (instance == null || instance.roomId != ev.RoomId)
|
|
|
|
|
return Ok(ToEventResult(ev, EventResultBroadcastNotMultiInstance));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ev.BroadcastingRoomInstanceId = roomInstanceId;
|
|
|
|
|
await db.SaveChangesAsync();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
await PlayerEventNotifications.PushToEventInstancesAsync(db, ev);
|
|
|
|
|
|
|
|
|
|
return Ok(ToEventResult(ev));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpPost("v1/deleteResponse"), Authorize]
|
|
|
|
|
[HttpDelete("v1/deleteResponse"), Authorize]
|
|
|
|
|
public async Task<IActionResult> DeleteEventResponse()
|
|
|
|
|
{
|
|
|
|
|
var userId = User.GetUserId();
|
|
|
|
|
if (userId == null) return Unauthorized();
|
|
|
|
|
|
|
|
|
|
var fields = await ReadEventFieldsAsync();
|
|
|
|
|
var eventId = GetEventLong(fields, "PlayerEventId", "playerEventId", "EventId", "eventId", "Id", "id") ?? 0;
|
|
|
|
|
if (eventId <= 0) eventId = await ReadEventIdFromRequestAsync();
|
|
|
|
|
if (eventId <= 0) return BadRequest(new { error = "PlayerEventId is required." });
|
|
|
|
|
|
|
|
|
|
var ev = await db.PlayerEvents.FirstOrDefaultAsync(x => x.PlayerEventId == eventId);
|
|
|
|
|
if (ev == null) return NotFound();
|
|
|
|
|
|
|
|
|
|
var existing = await db.PlayerEventResponses
|
|
|
|
|
.FirstOrDefaultAsync(x => x.PlayerEventId == eventId && x.PlayerId == userId.Value);
|
|
|
|
|
if (existing != null)
|
|
|
|
|
{
|
|
|
|
|
db.PlayerEventResponses.Remove(existing);
|
|
|
|
|
await db.SaveChangesAsync();
|
|
|
|
|
|
|
|
|
|
ev.AttendeeCount = await db.PlayerEventResponses
|
|
|
|
|
.CountAsync(x => x.PlayerEventId == eventId && x.Type == EventResponses.Yes);
|
|
|
|
|
await db.SaveChangesAsync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Ok(ToEventResult(ev));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpPost("v1/report"), Authorize]
|
|
|
|
|
public async Task<IActionResult> ReportEvent()
|
|
|
|
|
{
|
|
|
|
|
var reporterId = User.GetUserId();
|
|
|
|
|
if (reporterId == null) return Unauthorized();
|
|
|
|
|
|
|
|
|
|
var body = await ReadJsonBodyAsync();
|
|
|
|
|
var eventId = body == null ? null : GetBodyLong(body.Value, "PlayerEventId", "playerEventId");
|
|
|
|
|
if (eventId == null)
|
|
|
|
|
return Ok(new { success = false, error = "PlayerEventId is required" });
|
|
|
|
|
|
|
|
|
|
var ev = await db.PlayerEvents.FirstOrDefaultAsync(x => x.PlayerEventId == eventId);
|
|
|
|
|
if (ev == null)
|
|
|
|
|
return Ok(new { success = false, error = "No such event" });
|
|
|
|
|
|
|
|
|
|
int category = 0;
|
|
|
|
|
string? details = null;
|
|
|
|
|
if (body != null)
|
|
|
|
|
{
|
|
|
|
|
if (body.Value.TryGetProperty("ReportCategory", out var catRaw) &&
|
|
|
|
|
long.TryParse(catRaw.ToString(), out var catParsed))
|
|
|
|
|
category = (int)catParsed;
|
|
|
|
|
if (body.Value.TryGetProperty("Details", out var detailsRaw) &&
|
|
|
|
|
detailsRaw.ValueKind == JsonValueKind.String)
|
|
|
|
|
details = detailsRaw.GetString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Ok(new { success = true, error = string.Empty });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpPost("v1/bulkInvite"), Authorize]
|
|
|
|
|
public async Task<IActionResult> BulkInvite()
|
|
|
|
|
{
|
|
|
|
|
var userId = User.GetUserId();
|
|
|
|
|
if (userId == null) return Unauthorized();
|
|
|
|
|
|
|
|
|
|
var fields = await ReadEventFieldsAsync();
|
|
|
|
|
var eventIdRaw = GetEventField(fields, "PlayerEventId", "playerEventId", "EventId", "eventId");
|
|
|
|
|
if (!long.TryParse(eventIdRaw, out var eventId) || eventId <= 0)
|
|
|
|
|
return BadRequest(new { error = "PlayerEventId is required." });
|
|
|
|
|
|
|
|
|
|
var ev = await db.PlayerEvents.FirstOrDefaultAsync(x => x.PlayerEventId == eventId);
|
|
|
|
|
if (ev == null) return NotFound();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!await CanInviteToEventAsync(ev, userId.Value))
|
|
|
|
|
return StatusCode(StatusCodes.Status403Forbidden, new Dictionary<string, object?>
|
|
|
|
|
{
|
|
|
|
|
["error"] = "That event belongs to another player.",
|
|
|
|
|
["success"] = false,
|
|
|
|
|
["value"] = null,
|
|
|
|
|
["PlayerEventId"] = ev.PlayerEventId,
|
|
|
|
|
["CreatorPlayerId"] = ev.CreatorPlayerId
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var invitedPlayerIds = await ReadInvitedPlayerIdsAsync();
|
|
|
|
|
if (invitedPlayerIds.Count == 0)
|
|
|
|
|
return BadRequest(new { error = "At least one invited player is required." });
|
|
|
|
|
|
|
|
|
|
var failedInvites = new List<object>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var invitedPlayers = new List<long>();
|
|
|
|
|
var validPlayerIds = invitedPlayerIds
|
|
|
|
|
.Where(playerId => playerId > 0 && playerId != userId.Value)
|
|
|
|
|
.Distinct()
|
|
|
|
|
.ToList();
|
|
|
|
|
var profiles = await db.Profiles.AsNoTracking()
|
|
|
|
|
.Where(profile => validPlayerIds.Contains(profile.accountId))
|
|
|
|
|
.Select(profile => profile.accountId)
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
var existingResponses = await db.PlayerEventResponses
|
|
|
|
|
.Where(response => response.PlayerEventId == eventId && validPlayerIds.Contains(response.PlayerId))
|
|
|
|
|
.ToDictionaryAsync(response => response.PlayerId);
|
|
|
|
|
|
|
|
|
|
foreach (var playerId in invitedPlayerIds.Distinct())
|
|
|
|
|
{
|
|
|
|
|
if (playerId <= 0 || playerId == userId.Value || !profiles.Contains(playerId))
|
|
|
|
|
{
|
|
|
|
|
failedInvites.Add(new { PlayerId = playerId });
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!existingResponses.ContainsKey(playerId))
|
|
|
|
|
{
|
|
|
|
|
existingResponses[playerId] = new PlayerEventResponse
|
|
|
|
|
{
|
|
|
|
|
PlayerEventId = eventId,
|
|
|
|
|
PlayerId = playerId,
|
|
|
|
|
Type = EventResponses.Pending
|
|
|
|
|
};
|
|
|
|
|
await db.PlayerEventResponses.AddAsync(existingResponses[playerId]);
|
|
|
|
|
invitedPlayers.Add(playerId);
|
|
|
|
|
}
|
|
|
|
|
else if (existingResponses[playerId].Type is not (EventResponses.Yes or EventResponses.Pending))
|
|
|
|
|
{
|
|
|
|
|
existingResponses[playerId].Type = EventResponses.Pending;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await db.SaveChangesAsync();
|
|
|
|
|
|
|
|
|
|
foreach (var playerId in invitedPlayers)
|
|
|
|
|
await PlayerEventNotifications.PushAsync(playerId,
|
|
|
|
|
PlayerEventNotifications.ResponseChanged(ev, existingResponses[playerId]));
|
|
|
|
|
|
|
|
|
|
foreach (var playerId in validPlayerIds.Where(profiles.Contains))
|
|
|
|
|
{
|
|
|
|
|
await Notify.SendMessage(playerId, new Message
|
|
|
|
|
{
|
|
|
|
|
FromPlayerId = userId.Value,
|
|
|
|
|
Type = MessageType.PlayerEventInvitation,
|
|
|
|
|
PlayerEventId = eventId
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Ok(new Dictionary<string, object?>
|
|
|
|
|
{
|
|
|
|
|
["FailedInvites"] = failedInvites,
|
|
|
|
|
["Result"] = 0
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<bool> CanInviteToEventAsync(PlayerEventDB ev, long userId)
|
|
|
|
|
{
|
|
|
|
|
if (ev.CreatorPlayerId == userId) return true;
|
|
|
|
|
|
|
|
|
|
if (await db.PlayerEventResponses
|
|
|
|
|
.AnyAsync(x => x.PlayerEventId == ev.PlayerEventId && x.PlayerId == userId))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (ev.ClubId is > 0)
|
|
|
|
|
{
|
|
|
|
|
var club = await ClubStore.GetAsync(db, ev.ClubId.Value);
|
|
|
|
|
if (club != null && ClubStore.GetMembershipType(club, userId) >= ClubMembershipTypes.Coowner)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return !await db.Profiles.AnyAsync(x => x.accountId == ev.CreatorPlayerId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<List<long>> ReadInvitedPlayerIdsAsync()
|
|
|
|
|
{
|
|
|
|
|
var ids = new List<long>();
|
|
|
|
|
if (Request.Body.CanSeek) Request.Body.Position = 0;
|
|
|
|
|
if (Request.HasFormContentType)
|
|
|
|
|
{
|
|
|
|
|
var form = await Request.ReadFormAsync();
|
|
|
|
|
foreach (var field in form.Where(field => field.Key.Equals("InvitedPlayerIds", StringComparison.OrdinalIgnoreCase) ||
|
|
|
|
|
field.Key.Equals("InvitedPlayerIds[]", StringComparison.OrdinalIgnoreCase)))
|
|
|
|
|
{
|
|
|
|
|
foreach (var value in field.Value)
|
|
|
|
|
if (long.TryParse(value, out var id)) ids.Add(id);
|
|
|
|
|
}
|
|
|
|
|
return ids;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Request.EnableBuffering();
|
|
|
|
|
using var reader = new StreamReader(Request.Body, leaveOpen: true);
|
|
|
|
|
var body = await reader.ReadToEndAsync();
|
|
|
|
|
if (Request.Body.CanSeek) Request.Body.Position = 0;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using var document = JsonDocument.Parse(body);
|
|
|
|
|
if (document.RootElement.ValueKind == JsonValueKind.Object)
|
|
|
|
|
{
|
|
|
|
|
foreach (var property in document.RootElement.EnumerateObject()
|
|
|
|
|
.Where(property => property.Name.Equals("InvitedPlayerIds", StringComparison.OrdinalIgnoreCase) ||
|
|
|
|
|
property.Name.Equals("InvitedPlayerIds[]", StringComparison.OrdinalIgnoreCase)))
|
|
|
|
|
{
|
|
|
|
|
if (property.Value.ValueKind != JsonValueKind.Array) continue;
|
|
|
|
|
foreach (var value in property.Value.EnumerateArray())
|
|
|
|
|
if (long.TryParse(value.ToString(), out var id)) ids.Add(id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (JsonException) { }
|
|
|
|
|
return ids;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1/event/{eventId}/responses"), Authorize]
|
|
|
|
|
[HttpGet("v1/{eventId:long}/responses"), Authorize]
|
|
|
|
|
public async Task<ActionResult<List<EventResponse>>> GetResponses(long eventId)
|
|
|
|
|
{
|
|
|
|
|
if (eventId == -1) return Ok(Array.Empty<EventResponse>());
|
|
|
|
|
|
|
|
|
|
var ev = await db.PlayerEvents.FirstOrDefaultAsync(x => x.PlayerEventId == eventId);
|
|
|
|
|
if (ev == null) return NotFound();
|
|
|
|
|
|
|
|
|
|
var responses = await db.PlayerEventResponses
|
|
|
|
|
.Where(x => x.PlayerEventId == eventId)
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
|
|
|
|
|
return Ok(responses.Select(ToEventResponse).ToList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1/-1/responses"), Authorize]
|
|
|
|
|
public IActionResult GetLegacyPlaceholderResponses() => Ok(Array.Empty<EventResponse>());
|
|
|
|
|
|
|
|
|
|
[HttpGet("v1/event/{eventId}/attendees"), Authorize]
|
|
|
|
|
[HttpGet("v1/{eventId:long}/attendees"), Authorize]
|
|
|
|
|
public async Task<ActionResult<List<long>>> GetAttendees(long eventId)
|
|
|
|
|
{
|
|
|
|
|
var ev = await db.PlayerEvents.FirstOrDefaultAsync(x => x.PlayerEventId == eventId);
|
|
|
|
|
if (ev == null) return NotFound();
|
|
|
|
|
|
|
|
|
|
var attendees = await db.PlayerEventResponses
|
|
|
|
|
.Where(x => x.PlayerEventId == eventId && x.Type == EventResponses.Yes)
|
|
|
|
|
.Select(x => x.PlayerId)
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
|
|
|
|
|
return Ok(attendees);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpPost("v2/delete/{eventId:long}"), Authorize]
|
|
|
|
|
[HttpDelete("v2/delete/{eventId:long}"), Authorize]
|
|
|
|
|
[HttpPost("v2/delete"), Authorize]
|
|
|
|
|
[HttpDelete("v2/delete"), Authorize]
|
|
|
|
|
[HttpPost("v2/{eventId:long}/delete"), Authorize]
|
|
|
|
|
[HttpDelete("v2/{eventId:long}/delete"), Authorize]
|
|
|
|
|
public async Task<IActionResult> DeleteEventV2(long eventId = 0)
|
|
|
|
|
{
|
|
|
|
|
var userId = User.GetUserId();
|
|
|
|
|
if (userId == null) return Unauthorized();
|
|
|
|
|
|
|
|
|
|
var id = eventId > 0 ? eventId : await ReadEventIdFromRequestAsync();
|
|
|
|
|
if (id <= 0) return NotFound();
|
|
|
|
|
|
|
|
|
|
var ev = await db.PlayerEvents.FirstOrDefaultAsync(x => x.PlayerEventId == id);
|
|
|
|
|
|
|
|
|
|
if (ev != null && ev.CreatorPlayerId != userId) return Forbid();
|
|
|
|
|
|
|
|
|
|
if (ev == null)
|
|
|
|
|
{
|
|
|
|
|
await PlayerEventNotifications.PushAsync(userId.Value, PlayerEventNotifications.Deleted(id));
|
|
|
|
|
return Ok(ToEventResult(AlreadyGone(id, userId.Value)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await DeleteEventRow(ev);
|
|
|
|
|
|
|
|
|
|
await PlayerEventNotifications.PushAsync(userId.Value, PlayerEventNotifications.Deleted(ev.PlayerEventId));
|
|
|
|
|
|
|
|
|
|
return Ok(ToEventResult(ev));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static PlayerEventDB AlreadyGone(long eventId, long creatorPlayerId) => new()
|
|
|
|
|
{
|
|
|
|
|
PlayerEventId = eventId,
|
|
|
|
|
Name = string.Empty,
|
|
|
|
|
Description = string.Empty,
|
|
|
|
|
ImageName = string.Empty,
|
|
|
|
|
CreatorPlayerId = creatorPlayerId,
|
|
|
|
|
TagsJson = "[]"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private async Task<long> ReadEventIdFromRequestAsync()
|
|
|
|
|
{
|
|
|
|
|
foreach (var key in new[] { "PlayerEventId", "playerEventId", "EventId", "eventId", "Id", "id" })
|
|
|
|
|
if (Request.Query.TryGetValue(key, out var query) &&
|
|
|
|
|
long.TryParse(query.FirstOrDefault(), out var queryId) && queryId > 0)
|
|
|
|
|
return queryId;
|
|
|
|
|
|
|
|
|
|
if (Request.ContentLength is > 0)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Request.EnableBuffering();
|
|
|
|
|
var fields = await ReadEventFieldsAsync();
|
|
|
|
|
var bodyId = GetEventLong(fields, "PlayerEventId", "playerEventId", "EventId", "eventId", "Id", "id") ?? 0;
|
|
|
|
|
Request.Body.Position = 0;
|
|
|
|
|
if (bodyId > 0) return bodyId;
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
try { Request.Body.Position = 0; } catch { }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpDelete("v1/event/{eventId}"), Authorize]
|
|
|
|
|
[HttpDelete("v1/{eventId:long}"), Authorize]
|
|
|
|
|
public async Task<IActionResult> DeleteEvent(long eventId)
|
|
|
|
|
{
|
|
|
|
|
var userId = User.GetUserId();
|
|
|
|
|
if (userId == null) return Unauthorized();
|
|
|
|
|
|
|
|
|
|
var ev = await db.PlayerEvents.FirstOrDefaultAsync(x => x.PlayerEventId == eventId);
|
|
|
|
|
if (ev == null) return NotFound();
|
|
|
|
|
|
|
|
|
|
if (ev.CreatorPlayerId != userId)
|
|
|
|
|
return Forbid();
|
|
|
|
|
|
|
|
|
|
await DeleteEventRow(ev);
|
|
|
|
|
|
|
|
|
|
await PlayerEventNotifications.PushAsync(userId.Value, PlayerEventNotifications.Deleted(ev.PlayerEventId));
|
|
|
|
|
|
|
|
|
|
return Ok();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task DeleteEventRow(PlayerEventDB ev)
|
|
|
|
|
{
|
|
|
|
|
var responses = await db.PlayerEventResponses.Where(x => x.PlayerEventId == ev.PlayerEventId).ToListAsync();
|
|
|
|
|
db.PlayerEventResponses.RemoveRange(responses);
|
|
|
|
|
db.PlayerEvents.Remove(ev);
|
|
|
|
|
await db.SaveChangesAsync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<Dictionary<string, string>> ReadEventFieldsAsync()
|
|
|
|
|
{
|
|
|
|
|
var fields = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
|
Request.EnableBuffering();
|
|
|
|
|
|
|
|
|
|
foreach (var kv in Request.Query)
|
|
|
|
|
fields[kv.Key] = kv.Value.ToString();
|
|
|
|
|
|
|
|
|
|
if (Request.HasFormContentType)
|
|
|
|
|
{
|
|
|
|
|
var form = await Request.ReadFormAsync();
|
|
|
|
|
foreach (var kv in form)
|
|
|
|
|
fields[kv.Key] = kv.Value.ToString();
|
|
|
|
|
if (Request.Body.CanSeek) Request.Body.Position = 0;
|
|
|
|
|
return fields;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Request.ContentLength == 0) return fields;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using var reader = new StreamReader(Request.Body, leaveOpen: true);
|
|
|
|
|
var body = await reader.ReadToEndAsync();
|
|
|
|
|
if (Request.Body.CanSeek) Request.Body.Position = 0;
|
|
|
|
|
if (string.IsNullOrWhiteSpace(body)) return fields;
|
|
|
|
|
|
|
|
|
|
var trimmed = body.TrimStart();
|
|
|
|
|
if (trimmed.StartsWith("{", StringComparison.Ordinal))
|
|
|
|
|
{
|
|
|
|
|
using var doc = JsonDocument.Parse(body);
|
|
|
|
|
if (doc.RootElement.ValueKind == JsonValueKind.Object)
|
|
|
|
|
{
|
|
|
|
|
foreach (var prop in doc.RootElement.EnumerateObject())
|
|
|
|
|
{
|
|
|
|
|
fields[prop.Name] = prop.Value.ValueKind == JsonValueKind.String
|
|
|
|
|
? prop.Value.GetString() ?? ""
|
|
|
|
|
: prop.Value.ToString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (doc.RootElement.TryGetProperty("PlayerEvent", out var nested) &&
|
|
|
|
|
nested.ValueKind == JsonValueKind.Object)
|
|
|
|
|
{
|
|
|
|
|
foreach (var prop in nested.EnumerateObject())
|
|
|
|
|
{
|
|
|
|
|
if (fields.ContainsKey(prop.Name)) continue;
|
|
|
|
|
fields[prop.Name] = prop.Value.ValueKind == JsonValueKind.String
|
|
|
|
|
? prop.Value.GetString() ?? ""
|
|
|
|
|
: prop.Value.ToString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fields;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<JsonElement?> ReadJsonBodyAsync()
|
|
|
|
|
{
|
|
|
|
|
if (Request.ContentLength is not > 0) return null;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using var reader = new StreamReader(Request.Body);
|
|
|
|
|
var body = await reader.ReadToEndAsync();
|
|
|
|
|
if (string.IsNullOrWhiteSpace(body)) return null;
|
|
|
|
|
|
|
|
|
|
using var doc = JsonDocument.Parse(body);
|
|
|
|
|
return doc.RootElement.Clone();
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task ConsumeRequestBodyAsync()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (Request.HasFormContentType)
|
|
|
|
|
{
|
|
|
|
|
await Request.ReadFormAsync();
|
|
|
|
|
}
|
|
|
|
|
else if (Request.ContentLength is > 0)
|
|
|
|
|
{
|
|
|
|
|
using var reader = new StreamReader(Request.Body);
|
|
|
|
|
await reader.ReadToEndAsync();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static long? GetBodyLong(JsonElement body, params string[] names)
|
|
|
|
|
{
|
|
|
|
|
foreach (var name in names)
|
|
|
|
|
{
|
|
|
|
|
if (!body.TryGetProperty(name, out var value)) continue;
|
|
|
|
|
if (value.ValueKind == JsonValueKind.Number && value.TryGetInt64(out var number))
|
|
|
|
|
return number;
|
|
|
|
|
if (value.ValueKind == JsonValueKind.String &&
|
|
|
|
|
long.TryParse(value.GetString(), out var parsed))
|
|
|
|
|
return parsed;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string? GetEventField(Dictionary<string, string> fields, params string[] names)
|
|
|
|
|
{
|
|
|
|
|
foreach (var name in names)
|
|
|
|
|
{
|
|
|
|
|
if (fields.TryGetValue(name, out var value) && !string.IsNullOrWhiteSpace(value))
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static long? GetEventLong(Dictionary<string, string> fields, params string[] names)
|
|
|
|
|
{
|
|
|
|
|
var raw = GetEventField(fields, names);
|
|
|
|
|
return long.TryParse(raw, out var value) ? value : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static bool TryParseNullableEventId(string raw, out long? value)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(raw) || string.Equals(raw, "null", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
value = null;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (long.TryParse(raw, out var parsed) && parsed > 0)
|
|
|
|
|
{
|
|
|
|
|
value = parsed;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value = null;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int? GetEventInt(Dictionary<string, string> fields, params string[] names)
|
|
|
|
|
{
|
|
|
|
|
var raw = GetEventField(fields, names);
|
|
|
|
|
return int.TryParse(raw, out var value) ? value : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static bool ParseEventBoolean(string? raw)
|
|
|
|
|
=> bool.TryParse(raw, out var value) && value;
|
|
|
|
|
|
|
|
|
|
private static DateTime ParseEventDate(string? raw, DateTime fallback)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(raw)) return fallback;
|
|
|
|
|
return DateTime.TryParse(raw, out var parsed) ? EventClock.FromPostedTime(parsed) : fallback;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Accessibility ParseEventAccessibility(string? raw)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(raw)) return Accessibility.Public;
|
|
|
|
|
|
|
|
|
|
if (int.TryParse(raw, out var intValue) && Enum.IsDefined(typeof(Accessibility), intValue))
|
|
|
|
|
return (Accessibility)intValue;
|
|
|
|
|
|
|
|
|
|
return raw.Trim().ToLowerInvariant() switch
|
|
|
|
|
{
|
|
|
|
|
"public" => Accessibility.Public,
|
|
|
|
|
"private" => Accessibility.Private,
|
|
|
|
|
"unlisted" or "unlised" => Accessibility.Unlised,
|
|
|
|
|
_ => Accessibility.Public
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|