mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-26 07:28:45 -07:00
4edf25b2d5
Targets Rec Room 2020.12.18 client.
Re-import after adding:
- DorkNet.ClientMod/dorknet-clientmod.json.template — config schema
the launcher's manifest-driven patcher renders into UserData/.
- tools/build-patcher-zip.ps1 — produces the dorknet-clientpatch-{key}.zip
Release asset the launcher fetches.
- .github/workflows/release.yml — auto-publishes both Release assets
on v1-december-* tag push.
Scrubbed via maintainer-side scrub-for-public.ps1: same drop rules as
the prior import, plus build-patcher-zip.ps1 added to the tools/
allow-list so it survives the scrub.
158 lines
5.9 KiB
C#
158 lines
5.9 KiB
C#
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using System.Security.Cryptography;
|
|
using System.Text.Json;
|
|
using DorkNet.Server.Auth;
|
|
using DorkNet.Server.Data;
|
|
using DorkNet.Server.Data.Entities;
|
|
|
|
namespace DorkNet.Server.Controllers.API.Compatibility;
|
|
|
|
[ApiController]
|
|
public class CompatibilityFeatureController(DorkNetDbContext db) : ControllerBase
|
|
{
|
|
[HttpPost("api/banappeal/generateCode")]
|
|
[Authorize]
|
|
public async Task<IActionResult> GenerateBanAppealCode()
|
|
{
|
|
var pid = this.RequireCurrentPlayerId();
|
|
var code = $"BA-{RandomNumberGenerator.GetInt32(100000, 999999)}";
|
|
db.PlayerSettings.Add(new PlayerSettingEntity
|
|
{
|
|
PlayerId = pid,
|
|
Key = $"banappeal:{DateTime.UtcNow:yyyyMMddHHmmss}",
|
|
Value = code,
|
|
});
|
|
await db.SaveChangesAsync();
|
|
return Ok(new { value = code });
|
|
}
|
|
|
|
[HttpPost("api/CampusCard/v1/UpdateAndGetSubscription")]
|
|
[Authorize]
|
|
[Consumes("application/json", "application/x-www-form-urlencoded", "multipart/form-data")]
|
|
public async Task<IActionResult> UpdateAndGetCampusCardSubscription()
|
|
{
|
|
var pid = this.RequireCurrentPlayerId();
|
|
var req = await ReadCampusCardRequestAsync();
|
|
var targetId = req.PlatformAccountSubscribedPlayerId > 0
|
|
? req.PlatformAccountSubscribedPlayerId
|
|
: pid;
|
|
|
|
if (targetId != pid && req.Subscription)
|
|
{
|
|
var exists = await db.Subscriptions.AnyAsync(s =>
|
|
s.SubscriberPlayerId == pid && s.TargetPlayerId == targetId);
|
|
if (!exists)
|
|
{
|
|
db.Subscriptions.Add(new SubscriptionEntity
|
|
{
|
|
SubscriberPlayerId = pid,
|
|
TargetPlayerId = targetId,
|
|
});
|
|
await db.SaveChangesAsync();
|
|
}
|
|
}
|
|
else if (targetId != pid && !req.Subscription)
|
|
{
|
|
await db.Subscriptions
|
|
.Where(s => s.SubscriberPlayerId == pid && s.TargetPlayerId == targetId)
|
|
.ExecuteDeleteAsync();
|
|
}
|
|
|
|
// 2020.12 deserializer for this response expects `subscription` to be a
|
|
// nested OBJECT (Subscription DTO with subscriptionId/recNetPlayerId/...
|
|
// fields), NOT a boolean. Sending a bool throws InvalidCastException
|
|
// on the client ("Unable to cast object of type 'Boolean' to type
|
|
// 'Dictionary`2'"). Send null when there's no active subscription —
|
|
// the client's generic-cast helper returns default(T) which is fine.
|
|
return Ok(new
|
|
{
|
|
subscription = (object?)null,
|
|
platformAccountSubscribedPlayerId = targetId,
|
|
});
|
|
}
|
|
|
|
[HttpPost("api/clubreporting/v1/report")]
|
|
[Authorize]
|
|
[Consumes("application/json", "application/x-www-form-urlencoded", "multipart/form-data")]
|
|
public async Task<IActionResult> ClubReport()
|
|
{
|
|
var pid = this.RequireCurrentPlayerId();
|
|
var req = await ReadClubReportAsync();
|
|
var club = req.ClubId > 0
|
|
? await db.Clubs.FirstOrDefaultAsync(c => c.Id == req.ClubId)
|
|
: null;
|
|
if (club is null) return Ok(new { Success = false, Message = "club_not_found" });
|
|
|
|
var message = $"Club report: {req.Message ?? string.Empty}".Trim();
|
|
if (message.Length > 1000) message = message[..1000];
|
|
db.Reports.Add(new ReportEntity
|
|
{
|
|
ReporterPlayerId = pid,
|
|
TargetPlayerId = club.CreatorPlayerId,
|
|
Category = req.ReportCategory,
|
|
Message = message,
|
|
});
|
|
await db.SaveChangesAsync();
|
|
return Ok(new { Success = true, Message = string.Empty });
|
|
}
|
|
|
|
private async Task<CampusCardRequest> ReadCampusCardRequestAsync()
|
|
{
|
|
if (Request.HasFormContentType)
|
|
{
|
|
var form = await Request.ReadFormAsync();
|
|
return new CampusCardRequest
|
|
{
|
|
Subscription = bool.TryParse(form["subscription"].FirstOrDefault(), out var s) && s,
|
|
PlatformAccountSubscribedPlayerId = long.TryParse(
|
|
form["platformAccountSubscribedPlayerId"].FirstOrDefault(), out var id) ? id : 0,
|
|
};
|
|
}
|
|
try
|
|
{
|
|
return await JsonSerializer.DeserializeAsync<CampusCardRequest>(
|
|
Request.Body,
|
|
new JsonSerializerOptions { PropertyNameCaseInsensitive = true }) ?? new CampusCardRequest();
|
|
}
|
|
catch (JsonException) { return new CampusCardRequest(); }
|
|
}
|
|
|
|
private async Task<ClubReportRequest> ReadClubReportAsync()
|
|
{
|
|
if (Request.HasFormContentType)
|
|
{
|
|
var form = await Request.ReadFormAsync();
|
|
return new ClubReportRequest
|
|
{
|
|
ClubId = long.TryParse(form["clubId"].FirstOrDefault()
|
|
?? form["ClubId"].FirstOrDefault(), out var clubId) ? clubId : 0,
|
|
ReportCategory = int.TryParse(form["reportCategory"].FirstOrDefault()
|
|
?? form["ReportCategory"].FirstOrDefault(), out var cat) ? cat : 5,
|
|
Message = form["message"].FirstOrDefault() ?? form["Message"].FirstOrDefault(),
|
|
};
|
|
}
|
|
try
|
|
{
|
|
return await JsonSerializer.DeserializeAsync<ClubReportRequest>(
|
|
Request.Body,
|
|
new JsonSerializerOptions { PropertyNameCaseInsensitive = true }) ?? new ClubReportRequest();
|
|
}
|
|
catch (JsonException) { return new ClubReportRequest(); }
|
|
}
|
|
|
|
private sealed class CampusCardRequest
|
|
{
|
|
public bool Subscription { get; set; }
|
|
public long PlatformAccountSubscribedPlayerId { get; set; }
|
|
}
|
|
|
|
private sealed class ClubReportRequest
|
|
{
|
|
public long ClubId { get; set; }
|
|
public int ReportCategory { get; set; } = 5;
|
|
public string? Message { get; set; }
|
|
}
|
|
}
|