diff --git a/Net.Vatprc.Uniapi/Controllers/SectorController.cs b/Net.Vatprc.Uniapi/Controllers/SectorController.cs
new file mode 100644
index 0000000..e9eb098
--- /dev/null
+++ b/Net.Vatprc.Uniapi/Controllers/SectorController.cs
@@ -0,0 +1,45 @@
+using Net.Vatprc.Uniapi.Models;
+using Net.Vatprc.Uniapi.Services;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using System.Collections.Immutable;
+using System.Security.Claims;
+using Net.Vatprc.Uniapi.Utils;
+using System.Diagnostics.CodeAnalysis;
+
+namespace Net.Vatprc.Uniapi.Controllers;
+
+///
+/// Sector information.
+///
+[ApiController, Route("api/sectors")]
+public class SectorController(
+ VATPRCContext DbContext,
+ VatsimService VatsimService) : ControllerBase
+{
+ public record SectorPermissionResponse
+ {
+ public required bool HasPermission { get; set; }
+
+ [SetsRequiredMembers]
+ public SectorPermissionResponse(bool hasPermission)
+ {
+ HasPermission = hasPermission;
+ }
+ }
+
+ [HttpGet("current/permission")]
+ public async Task GetPermission()
+ {
+ var user = await DbContext.User.FindAsync(this.GetUserId()) ??
+ throw new ApiError.UserNotFound(this.GetUserId());
+ var controllers = await VatsimService.GetAtcList();
+ var atc = controllers.FirstOrDefault(c => c.Id.ToString() == user.Cid);
+ if (atc == null)
+ {
+ return new SectorPermissionResponse(false);
+ }
+ var hasPermission = atc.Roles.Any(r => r.Name == "Online Permission" || r.Name == "ATC Student");
+ return new SectorPermissionResponse(hasPermission);
+ }
+}
diff --git a/Net.Vatprc.Uniapi/Controllers/UserController.cs b/Net.Vatprc.Uniapi/Controllers/UserController.cs
index 129f889..c19456b 100644
--- a/Net.Vatprc.Uniapi/Controllers/UserController.cs
+++ b/Net.Vatprc.Uniapi/Controllers/UserController.cs
@@ -3,6 +3,7 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Immutable;
+using System.Security.Claims;
namespace Net.Vatprc.Uniapi.Controllers;
@@ -51,4 +52,13 @@ public async Task Get(Ulid id)
{
return new UserDto(await DbContext.User.FindAsync(id) ?? throw new ApiError.UserNotFound(id));
}
+
+ [HttpGet("me")]
+ public async Task Me()
+ {
+ var subject = User.FindFirstValue(ClaimTypes.NameIdentifier);
+ var userId = Ulid.Parse(subject);
+ var user = await DbContext.User.FindAsync(userId);
+ return new UserDto(user ?? throw new ApiError.UserNotFound(userId));
+ }
}
diff --git a/Net.Vatprc.Uniapi/Services/VatsimData.cs b/Net.Vatprc.Uniapi/Services/VatsimData.cs
index e86c399..7d2f9be 100644
--- a/Net.Vatprc.Uniapi/Services/VatsimData.cs
+++ b/Net.Vatprc.Uniapi/Services/VatsimData.cs
@@ -6,7 +6,7 @@
namespace Net.Vatprc.Uniapi.Services.VatsimData;
-public partial class VatsimData
+public class VatsimData
{
[JsonPropertyName("general")]
public General General { get; set; }
@@ -39,7 +39,7 @@ public partial class VatsimData
public Rating[] MilitaryRatings { get; set; }
}
-public partial class Atc
+public class Atc
{
[JsonPropertyName("cid")]
public long Cid { get; set; }
@@ -78,7 +78,7 @@ public partial class Atc
public DateTimeOffset LogonTime { get; set; }
}
-public partial class Facility
+public class Facility
{
[JsonPropertyName("id")]
public long Id { get; set; }
@@ -90,7 +90,7 @@ public partial class Facility
public string Long { get; set; }
}
-public partial class General
+public class General
{
[JsonPropertyName("version")]
public long Version { get; set; }
@@ -111,7 +111,7 @@ public partial class General
public long UniqueUsers { get; set; }
}
-public partial class Rating
+public class Rating
{
[JsonPropertyName("id")]
public long Id { get; set; }
@@ -123,7 +123,7 @@ public partial class Rating
public string LongName { get; set; }
}
-public partial class Pilot
+public class Pilot
{
[JsonPropertyName("cid")]
public long Cid { get; set; }
@@ -177,7 +177,7 @@ public partial class Pilot
public DateTimeOffset LastUpdated { get; set; }
}
-public partial class FlightPlan
+public class FlightPlan
{
[JsonPropertyName("flight_rules")]
public string FlightRules { get; set; }
@@ -228,7 +228,7 @@ public partial class FlightPlan
public string AssignedTransponder { get; set; }
}
-public partial class Prefile
+public class Prefile
{
[JsonPropertyName("cid")]
public long Cid { get; set; }
@@ -246,7 +246,7 @@ public partial class Prefile
public DateTimeOffset LastUpdated { get; set; }
}
-public partial class ServerElement
+public class ServerElement
{
[JsonPropertyName("ident")]
public string Ident { get; set; }
@@ -270,7 +270,7 @@ public partial class ServerElement
public bool IsSweatbox { get; set; }
}
-public partial class AtcSchedule
+public class AtcSchedule
{
[JsonPropertyName("callsign")]
public string Callsign { get; set; }
@@ -294,7 +294,7 @@ public partial class AtcSchedule
public User User { get; set; }
}
-public partial class User
+public class User
{
[JsonPropertyName("id")]
public long Id { get; set; }
@@ -305,3 +305,30 @@ public partial class User
[JsonPropertyName("last_name")]
public string LastName { get; set; }
}
+
+public class Controller
+{
+ [JsonPropertyName("id")]
+ public long Id { get; set; }
+
+ [JsonPropertyName("first_name")]
+ public string FirstName { get; set; }
+
+ [JsonPropertyName("last_name")]
+ public string LastName { get; set; }
+
+ [JsonPropertyName("roles")]
+ public Role[] Roles { get; set; }
+}
+
+public class Role
+{
+ [JsonPropertyName("id")]
+ public long Id { get; set; }
+
+ [JsonPropertyName("name")]
+ public string Name { get; set; }
+
+ [JsonPropertyName("expires")]
+ public DateTimeOffset? Expires { get; set; }
+}
diff --git a/Net.Vatprc.Uniapi/Services/VatsimService.cs b/Net.Vatprc.Uniapi/Services/VatsimService.cs
index 3ee840b..936128f 100644
--- a/Net.Vatprc.Uniapi/Services/VatsimService.cs
+++ b/Net.Vatprc.Uniapi/Services/VatsimService.cs
@@ -38,4 +38,16 @@ public static WebApplicationBuilder ConfigureOn(WebApplicationBuilder builder)
}) ?? throw new Exception("Unexpected null on fetch vatprc data");
return result;
}
+
+ public async Task> GetAtcList()
+ {
+ var result = await Cache.GetOrCreateAsync("controllers", async entry =>
+ {
+ entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1);
+ return await "https://atcapi.vatprc.net/v1/public/controllers"
+ .WithHeader("User-Agent", UniapiUserAgent)
+ .GetJsonAsync>();
+ }) ?? throw new Exception("Unexpected null on fetch vatprc data");
+ return result;
+ }
}