using System.Net; using collAnon.Client.Services; using decePubClient.Extensions; using decePubClient.Models; using PrivaPub.ClientModels; using PrivaPub.ClientModels.Group; namespace decePubClient.Services { /// The persona's communities and circles (/clientapi/group): made, joined by invitation, edited and left; /// for their owners and moderators, who is in them and who asks to join. public class GroupService(IHttpService httpService, ILoggingService logger, CoalescingStringLocalizer localizer) { /// The persona's groups, communities first; empty on failure. public async Task> List(string personaId, CancellationToken cancellationToken = default) { if (personaId is null) return []; using var response = await httpService.Get(APIs.ClientApi.GET_Groups, [$"avatarId={Uri.EscapeDataString(personaId)}"], cancellationToken: cancellationToken); if (!response.IsSuccessStatusCode) { var result = await response.Content.ReadWebResult(response.StatusCode, localizer, cancellationToken); if (result.StatusCode is not (int)HttpStatusCode.Gone) await logger.ProcessWarning(result.ToString(localizer), $"{nameof(GroupService)}.{nameof(List)}", cancellationToken); return []; } var groups = await response.DefaultReadFromJsonAsync>(cancellationToken) ?? []; return [.. groups.OrderByDescending(g => g.IsCommunity).ThenBy(g => g.Name ?? g.UserName)]; } /// Makes a community or a circle owned by the persona; Data is the ViewGroup. public Task Insert(InsertGroupForm form, CancellationToken cancellationToken = default) => GroupResult(APIs.ClientApi.POST_InsertGroup, form, cancellationToken); /// Changes a group the persona runs; Data is the ViewGroup. public Task Update(UpdateGroupForm form, CancellationToken cancellationToken = default) => GroupResult(APIs.ClientApi.POST_UpdateGroup, form, cancellationToken); /// Joins a group by its invitation (and its password, when it has one); Data is the ViewGroup. public Task Join(JoinGroupForm form, CancellationToken cancellationToken = default) => GroupResult(APIs.ClientApi.POST_JoinGroup, form, cancellationToken); public Task Leave(string personaId, string groupId, CancellationToken cancellationToken = default) => Membership(APIs.ClientApi.POST_LeaveGroup, personaId, groupId, null, cancellationToken); /// Lets in someone who asked to join a group the persona runs. public Task Approve(string personaId, string groupId, string actorUri, CancellationToken cancellationToken = default) => Membership(APIs.ClientApi.POST_ApproveGroupMember, personaId, groupId, actorUri, cancellationToken); /// Declines a request to join; the asker's server is told. public Task Reject(string personaId, string groupId, string actorUri, CancellationToken cancellationToken = default) => Membership(APIs.ClientApi.POST_RejectGroupMember, personaId, groupId, actorUri, cancellationToken); /// Takes a member out of a group the persona runs. public Task Remove(string personaId, string groupId, string actorUri, CancellationToken cancellationToken = default) => Membership(APIs.ClientApi.POST_RemoveGroupMember, personaId, groupId, actorUri, cancellationToken); /// Who is in a group the persona runs, and who asks to join; empty on failure. public async Task> Members(string personaId, string groupId, CancellationToken cancellationToken = default) { using var response = await httpService.Get(APIs.ClientApi.GET_GroupMembers, [$"avatarId={Uri.EscapeDataString(personaId)}", $"groupId={Uri.EscapeDataString(groupId)}"], cancellationToken: cancellationToken); if (!response.IsSuccessStatusCode) { var result = await response.Content.ReadWebResult(response.StatusCode, localizer, cancellationToken); await logger.ProcessWarning(result.ToString(localizer), $"{nameof(GroupService)}.{nameof(Members)}", cancellationToken); return []; } return await response.DefaultReadFromJsonAsync>(cancellationToken) ?? []; } async Task GroupResult(string route, object form, CancellationToken cancellationToken) { using var response = await httpService.Post(route, form, cancellationToken: cancellationToken); if (!response.IsSuccessStatusCode) return await response.Content.ReadWebResult(response.StatusCode, localizer, cancellationToken); return new WebResult { Data = await response.DefaultReadFromJsonAsync(cancellationToken) }; } async Task Membership(string route, string personaId, string groupId, string actorUri, CancellationToken cancellationToken) { using var response = await httpService.Post(route, new GroupMembershipForm { AvatarId = personaId, GroupId = groupId, MemberActorURI = actorUri }, cancellationToken: cancellationToken); if (!response.IsSuccessStatusCode) return await response.Content.ReadWebResult(response.StatusCode, localizer, cancellationToken); return new WebResult(); } } }