139 lines
5.5 KiB
C#
139 lines
5.5 KiB
C#
|
|
using Refit;
|
||
|
|
|
||
|
|
namespace OTSSignsOrchestrator.Server.Clients;
|
||
|
|
|
||
|
|
// ── Request DTOs ────────────────────────────────────────────────────────────
|
||
|
|
public record CreateUserRequest(
|
||
|
|
string UserName,
|
||
|
|
string Email,
|
||
|
|
string Password,
|
||
|
|
int UserTypeId,
|
||
|
|
int HomePageId);
|
||
|
|
|
||
|
|
public record UpdateUserRequest(
|
||
|
|
string? UserName,
|
||
|
|
string? Email,
|
||
|
|
string? Password,
|
||
|
|
int? UserTypeId,
|
||
|
|
int? HomePageId,
|
||
|
|
int? Retired);
|
||
|
|
|
||
|
|
public record CreateGroupRequest(string Group, string? Description);
|
||
|
|
|
||
|
|
public record AssignMemberRequest(int[] UserId);
|
||
|
|
|
||
|
|
public record SetAclRequest(string[] ObjectId, string[] PermissionsId);
|
||
|
|
|
||
|
|
public record CreateApplicationRequest(string Name);
|
||
|
|
|
||
|
|
public record UpdateSettingsRequest(Dictionary<string, string> Settings);
|
||
|
|
|
||
|
|
public record CreateDisplayRequest(string Display, string? Description);
|
||
|
|
|
||
|
|
// ── Xibo CMS Refit Interface ────────────────────────────────────────────────
|
||
|
|
// CRITICAL: GET /api/application is BLOCKED — only POST and DELETE exist.
|
||
|
|
// All group endpoints use /api/group, NOT /api/usergroup.
|
||
|
|
// Feature assignment is POST /api/group/{id}/acl, NOT /features.
|
||
|
|
// Xibo paginates at 10 items by default — always pass start + length params.
|
||
|
|
[Headers("Authorization: Bearer")]
|
||
|
|
public interface IXiboApiClient
|
||
|
|
{
|
||
|
|
// ── About ───────────────────────────────────────────────────────────────
|
||
|
|
[Get("/about")]
|
||
|
|
Task<ApiResponse<object>> GetAboutAsync();
|
||
|
|
|
||
|
|
// ── Users ───────────────────────────────────────────────────────────────
|
||
|
|
[Get("/user")]
|
||
|
|
Task<List<Dictionary<string, object>>> GetUsersAsync(
|
||
|
|
[AliasAs("start")] int? start = 0,
|
||
|
|
[AliasAs("length")] int? length = 200);
|
||
|
|
|
||
|
|
[Post("/user")]
|
||
|
|
Task<ApiResponse<Dictionary<string, object>>> CreateUserAsync(
|
||
|
|
[Body(BodySerializationMethod.UrlEncoded)] CreateUserRequest body);
|
||
|
|
|
||
|
|
[Put("/user/{userId}")]
|
||
|
|
Task<ApiResponse<Dictionary<string, object>>> UpdateUserAsync(
|
||
|
|
int userId,
|
||
|
|
[Body(BodySerializationMethod.UrlEncoded)] UpdateUserRequest body);
|
||
|
|
|
||
|
|
[Delete("/user/{userId}")]
|
||
|
|
Task DeleteUserAsync(int userId);
|
||
|
|
|
||
|
|
// ── Groups (NOT /usergroup) ─────────────────────────────────────────────
|
||
|
|
[Get("/group")]
|
||
|
|
Task<List<Dictionary<string, object>>> GetGroupsAsync(
|
||
|
|
[AliasAs("start")] int? start = 0,
|
||
|
|
[AliasAs("length")] int? length = 200);
|
||
|
|
|
||
|
|
[Post("/group")]
|
||
|
|
Task<ApiResponse<Dictionary<string, object>>> CreateGroupAsync(
|
||
|
|
[Body(BodySerializationMethod.UrlEncoded)] CreateGroupRequest body);
|
||
|
|
|
||
|
|
[Delete("/group/{groupId}")]
|
||
|
|
Task DeleteGroupAsync(int groupId);
|
||
|
|
|
||
|
|
[Post("/group/members/assign/{groupId}")]
|
||
|
|
Task<ApiResponse<object>> AssignUserToGroupAsync(
|
||
|
|
int groupId,
|
||
|
|
[Body(BodySerializationMethod.UrlEncoded)] AssignMemberRequest body);
|
||
|
|
|
||
|
|
// ACL — NOT /features
|
||
|
|
[Post("/group/{groupId}/acl")]
|
||
|
|
Task<ApiResponse<object>> SetGroupAclAsync(
|
||
|
|
int groupId,
|
||
|
|
[Body(BodySerializationMethod.UrlEncoded)] SetAclRequest body);
|
||
|
|
|
||
|
|
// ── Displays ────────────────────────────────────────────────────────────
|
||
|
|
[Get("/display")]
|
||
|
|
Task<List<Dictionary<string, object>>> GetDisplaysAsync(
|
||
|
|
[AliasAs("start")] int? start = 0,
|
||
|
|
[AliasAs("length")] int? length = 200,
|
||
|
|
[AliasAs("authorised")] int? authorised = null);
|
||
|
|
|
||
|
|
// ── Applications (POST + DELETE only — GET is BLOCKED) ──────────────────
|
||
|
|
[Post("/application")]
|
||
|
|
Task<ApiResponse<Dictionary<string, object>>> CreateApplicationAsync(
|
||
|
|
[Body(BodySerializationMethod.UrlEncoded)] CreateApplicationRequest body);
|
||
|
|
|
||
|
|
[Delete("/application/{key}")]
|
||
|
|
Task DeleteApplicationAsync(string key);
|
||
|
|
|
||
|
|
// ── Settings ────────────────────────────────────────────────────────────
|
||
|
|
[Get("/settings")]
|
||
|
|
Task<ApiResponse<object>> GetSettingsAsync();
|
||
|
|
|
||
|
|
[Put("/settings")]
|
||
|
|
Task<ApiResponse<object>> UpdateSettingsAsync(
|
||
|
|
[Body(BodySerializationMethod.UrlEncoded)] UpdateSettingsRequest body);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ── Pagination helper ───────────────────────────────────────────────────────
|
||
|
|
public static class XiboApiClientExtensions
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// Pages through a Xibo list endpoint until a page returns fewer items than pageSize.
|
||
|
|
/// </summary>
|
||
|
|
public static async Task<List<T>> GetAllPagesAsync<T>(
|
||
|
|
this IXiboApiClient client,
|
||
|
|
Func<int, int, Task<List<T>>> listMethod,
|
||
|
|
int pageSize = 200)
|
||
|
|
{
|
||
|
|
var all = new List<T>();
|
||
|
|
var start = 0;
|
||
|
|
|
||
|
|
while (true)
|
||
|
|
{
|
||
|
|
var page = await listMethod(start, pageSize);
|
||
|
|
all.AddRange(page);
|
||
|
|
|
||
|
|
if (page.Count < pageSize)
|
||
|
|
break;
|
||
|
|
|
||
|
|
start += pageSize;
|
||
|
|
}
|
||
|
|
|
||
|
|
return all;
|
||
|
|
}
|
||
|
|
}
|