mirror of
https://github.com/JogmansonReal/Radicade.git
synced 2026-10-26 07:29:00 -07:00
289 lines
8.2 KiB
C#
289 lines
8.2 KiB
C#
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using RadicadeServer.DB;
|
|
using RadicadeServer.Extensions;
|
|
using RadicadeServer.API.Notifications;
|
|
using RadicadeServer.RecNet.Enums.Messages;
|
|
using RadicadeServer.RecNet.Enums.Moderation;
|
|
using RadicadeServer.RecNet.Messages;
|
|
using RadicadeServer.RecNet.Moderation;
|
|
using RadicadeServer.RecNet.Notifications;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Nodes;
|
|
using System.Text.Json.Serialization;
|
|
using RadicadeServer.RecNet.Responses;
|
|
|
|
namespace RadicadeServer.API.Moderation
|
|
{
|
|
[Route("api/playerReputation")]
|
|
public class ReputationAPI : Controller
|
|
{
|
|
RecDBContext db;
|
|
public ReputationAPI(RecDBContext context) {
|
|
this.db = context;
|
|
}
|
|
|
|
[HttpGet("v1/{id}")]
|
|
public IActionResult GetReputation(long id)
|
|
{
|
|
var reputation = db.Reputations.FirstOrDefault((x) => x.AccountId == id);
|
|
reputation ??= new Reputation { AccountId = id };
|
|
return Ok(CreateClientReputation(reputation.ForClient()));
|
|
}
|
|
|
|
[HttpPost("v1/bulk")]
|
|
public IActionResult GetBulkReputation([FromForm] long[] ids)
|
|
{
|
|
var reputations = new List<ClientReputation>();
|
|
foreach (var id in ids)
|
|
{
|
|
var reputation = db.Reputations.FirstOrDefault((x) => x.AccountId == id);
|
|
reputation ??= new Reputation { AccountId = id };
|
|
reputations.Add(CreateClientReputation(reputation.ForClient()));
|
|
}
|
|
return Ok(reputations);
|
|
}
|
|
|
|
[HttpGet("v2/bulk")]
|
|
public IActionResult GetBulkReputationV2([FromQuery] long[] id)
|
|
{
|
|
var reputations = new List<ClientReputation>();
|
|
foreach (var i in id)
|
|
{
|
|
var reputation = db.Reputations.FirstOrDefault((x) => x.AccountId == i);
|
|
reputation ??= new Reputation { AccountId = i };
|
|
reputations.Add(CreateClientReputation(reputation.ForClient()));
|
|
}
|
|
return Ok(reputations);
|
|
}
|
|
|
|
private static ClientReputation CreateClientReputation(Reputation reputation) => new()
|
|
{
|
|
Id = reputation.AccountId,
|
|
AccountId = reputation.AccountId,
|
|
|
|
|
|
|
|
|
|
IsCheerful = true,
|
|
Noteriety = (float)reputation.Noteriety,
|
|
SelectedCheer = reputation.SelectedCheer,
|
|
|
|
|
|
|
|
CheerCredit = reputation.CheerCredit > 0 ? reputation.CheerCredit : 20,
|
|
|
|
|
|
|
|
CheerGeneral = reputation.CheerGeneral,
|
|
CheerHelpful = reputation.CheerHelpful,
|
|
CheerCreative = reputation.CheerCreative,
|
|
CheerGreatHost = reputation.CheerGreatHost,
|
|
CheerSportsman = reputation.CheerSportsman
|
|
};
|
|
|
|
private sealed class ClientReputation
|
|
{
|
|
public long Id { get; set; }
|
|
[JsonPropertyName("accountId")]
|
|
public long AccountId { get; set; }
|
|
public bool IsCheerful { get; set; }
|
|
public float Noteriety { get; set; }
|
|
public int SelectedCheer { get; set; }
|
|
public int CheerCredit { get; set; }
|
|
public int CheerGeneral { get; set; }
|
|
public int CheerHelpful { get; set; }
|
|
public int CheerCreative { get; set; }
|
|
public int CheerGreatHost { get; set; }
|
|
public int CheerSportsman { get; set; }
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly CheerCategory[] AwardableCheers =
|
|
{
|
|
CheerCategory.General, CheerCategory.Helpful, CheerCategory.Sportsman,
|
|
CheerCategory.GreatHost, CheerCategory.Creative
|
|
};
|
|
|
|
[HttpPost("~/api/PlayerCheer/v1/create")]
|
|
[HttpPost("v1/cheer"), Authorize]
|
|
public async Task<ActionResult<Success>> CheerPlayer()
|
|
{
|
|
var userId = User.GetUserId();
|
|
if (userId == null) return Unauthorized();
|
|
|
|
var request = await ReadRequestValuesAsync();
|
|
var values = request.Values;
|
|
var playerId = ReadLong(values, "playeridto", "playerid", "player", "targetplayerid", "accountid", "id");
|
|
var category = ReadInt(values, "category", "cheercategory", "cheer", "value");
|
|
|
|
if (playerId == null || category == null)
|
|
{
|
|
return BadRequest(Success.Error("No player or cheer category was given."));
|
|
}
|
|
|
|
if (playerId == userId) return BadRequest(Success.Error("You can't cheer yourself."));
|
|
|
|
var cheer = (CheerCategory)category.Value;
|
|
if (!AwardableCheers.Contains(cheer))
|
|
return BadRequest(Success.Error($"Unknown cheer category {category.Value}."));
|
|
|
|
var reputation = await db.Reputations.FirstOrDefaultAsync(x => x.AccountId == playerId);
|
|
if (reputation == null)
|
|
{
|
|
|
|
|
|
reputation = new Reputation { AccountId = playerId.Value };
|
|
await db.Reputations.AddAsync(reputation);
|
|
}
|
|
|
|
reputation.AddCheer(cheer);
|
|
|
|
await db.SaveChangesAsync();
|
|
|
|
|
|
|
|
|
|
|
|
await Notify.SendMessage(playerId.Value, new Message
|
|
{
|
|
FromPlayerId = userId.Value,
|
|
Type = MessageType.PlayerCheer,
|
|
Data = category.Value.ToString()
|
|
});
|
|
|
|
await Notify.SendAccountUpdate(playerId.Value);
|
|
await SendReputationUpdate(playerId.Value, reputation);
|
|
|
|
return Ok(Success.Ok);
|
|
}
|
|
|
|
private async Task<(Dictionary<string, string> Values, string Raw)> ReadRequestValuesAsync()
|
|
{
|
|
var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
foreach (var (key, value) in Request.RouteValues)
|
|
if (value != null) values[key] = value.ToString() ?? string.Empty;
|
|
|
|
foreach (var (key, value) in Request.Query)
|
|
values[key] = value.ToString();
|
|
|
|
Request.EnableBuffering();
|
|
|
|
string raw;
|
|
using (var reader = new StreamReader(Request.Body, Encoding.UTF8, detectEncodingFromByteOrderMarks: false, leaveOpen: true))
|
|
raw = (await reader.ReadToEndAsync()).Trim();
|
|
|
|
Request.Body.Position = 0;
|
|
|
|
if (raw.Length == 0) return (values, raw);
|
|
|
|
if (raw.StartsWith('{'))
|
|
{
|
|
try
|
|
{
|
|
if (JsonNode.Parse(raw) is JsonObject json)
|
|
{
|
|
foreach (var (key, value) in json)
|
|
values[key] = value?.ToString() ?? string.Empty;
|
|
return (values, raw);
|
|
}
|
|
}
|
|
catch (JsonException) { }
|
|
}
|
|
|
|
if (raw.Contains('='))
|
|
{
|
|
foreach (var pair in raw.Split('&', StringSplitOptions.RemoveEmptyEntries))
|
|
{
|
|
var parts = pair.Split('=', 2);
|
|
if (parts.Length == 2)
|
|
values[parts[0]] = Uri.UnescapeDataString(parts[1]);
|
|
}
|
|
return (values, raw);
|
|
}
|
|
|
|
values["category"] = raw;
|
|
return (values, raw);
|
|
}
|
|
|
|
private static int? ReadInt(Dictionary<string, string> values, params string[] keys)
|
|
{
|
|
foreach (var key in keys)
|
|
if (values.TryGetValue(key, out var raw) && int.TryParse(raw, out var parsed))
|
|
return parsed;
|
|
return null;
|
|
}
|
|
|
|
private static long? ReadLong(Dictionary<string, string> values, params string[] keys)
|
|
{
|
|
foreach (var key in keys)
|
|
if (values.TryGetValue(key, out var raw) && long.TryParse(raw, out var parsed))
|
|
return parsed;
|
|
return null;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[HttpPost("~/api/PlayerCheer/v1/SetSelectedCheer")]
|
|
[HttpPost("v1/selectedCheer"), HttpPost("v1/selectCheer"),
|
|
HttpPost("v1/selectedCheer/{category:int}"), HttpPut("v1/selectedCheer"), Authorize]
|
|
public async Task<ActionResult<Success>> SetSelectedCheer()
|
|
{
|
|
var userId = User.GetUserId();
|
|
if (userId == null) return Unauthorized();
|
|
|
|
var request = await ReadRequestValuesAsync();
|
|
var category = ReadInt(request.Values, "category", "cheercategory", "cheer", "value", "selectedcheer");
|
|
if (category == null)
|
|
{
|
|
return BadRequest(Success.Error("No cheer category was given."));
|
|
}
|
|
|
|
var reputation = await db.Reputations.FirstOrDefaultAsync(x => x.AccountId == userId);
|
|
if (reputation == null)
|
|
{
|
|
reputation = new Reputation
|
|
{
|
|
AccountId = userId.Value,
|
|
IsCheerful = true,
|
|
CheerCredit = 20
|
|
};
|
|
await db.Reputations.AddAsync(reputation);
|
|
}
|
|
|
|
reputation.SelectedCheer = category.Value;
|
|
await db.SaveChangesAsync();
|
|
|
|
await Notify.SendAccountUpdate(userId.Value);
|
|
await SendReputationUpdate(userId.Value, reputation);
|
|
|
|
return Ok(Success.Ok);
|
|
}
|
|
|
|
/// <summary>
|
|
/// The frame the cheer counters and the cheer badge are built from, pushed under
|
|
/// "ReputationUpdate" - the key the 2023 client registers a handler for. The account update
|
|
/// only carries the profile, so without this the cheer a player was just handed, and the
|
|
/// badge it unlocked, stayed invisible on the receiving client until their next login
|
|
/// refetched the reputation, which is what "not updated instantly" looked like.
|
|
/// </summary>
|
|
private static Task SendReputationUpdate(long accountId, Reputation reputation) =>
|
|
Notify.SendNotify(accountId, new Notification
|
|
{
|
|
Id = "ReputationUpdate",
|
|
Msg = CreateClientReputation(reputation.ForClient())
|
|
});
|
|
}
|
|
}
|