From a4ab7daffc7cc91d88e31163925564362b7c1a28 Mon Sep 17 00:00:00 2001 From: Stanley Dimant Date: Thu, 6 Oct 2022 16:37:40 +0200 Subject: [PATCH] add api changes for banning and moderators --- MareAPI | 2 +- MareSynchronos/MareSynchronos.csproj | 2 +- MareSynchronos/UI/GroupPanel.cs | 163 ++++++++++++------ .../ApiController.Functions.Callbacks.cs | 2 + .../WebAPI/ApiController.Functions.Groups.cs | 24 +++ 5 files changed, 143 insertions(+), 50 deletions(-) diff --git a/MareAPI b/MareAPI index fc47c86..1c3327f 160000 --- a/MareAPI +++ b/MareAPI @@ -1 +1 @@ -Subproject commit fc47c861b7f7464bde6913e547ac191ae24a14cb +Subproject commit 1c3327f9bc9e42d2d75886a01f72655c2c6fb0f3 diff --git a/MareSynchronos/MareSynchronos.csproj b/MareSynchronos/MareSynchronos.csproj index 0cb2bd2..c09e4bf 100644 --- a/MareSynchronos/MareSynchronos.csproj +++ b/MareSynchronos/MareSynchronos.csproj @@ -3,7 +3,7 @@ - 0.5.0 + 0.5.1 https://github.com/Penumbra-Sync/client diff --git a/MareSynchronos/UI/GroupPanel.cs b/MareSynchronos/UI/GroupPanel.cs index 37565b8..0e3dc40 100644 --- a/MareSynchronos/UI/GroupPanel.cs +++ b/MareSynchronos/UI/GroupPanel.cs @@ -28,7 +28,9 @@ namespace MareSynchronos.UI private bool _showModalEnterPassword; private bool _showModalCreateGroup; private bool _showModalChangePassword; + private bool _showModalBanUser; private string _newSyncShellPassword = string.Empty; + private string _banReason = string.Empty; private bool _isPasswordValid; private bool _errorGroupJoin; private bool _errorGroupCreate = false; @@ -270,12 +272,18 @@ namespace MareSynchronos.UI ImGui.Indent(collapseButton.X); if (ExpandedGroupState[group.GID]) { - pairsInGroup = pairsInGroup.OrderBy(p => string.Equals(p.UserUID, group.OwnedBy, StringComparison.Ordinal) ? 0 : 1).ThenBy(p => p.IsPinned ?? false ? 0 : 1).ThenBy(p => p.UserAlias ?? p.UserUID).ToList(); + pairsInGroup = pairsInGroup.OrderBy(p => string.Equals(p.UserUID, group.OwnedBy, StringComparison.Ordinal) ? 0 : 1) + .ThenBy(p => p.IsModerator ?? false ? 0 : 1) + .ThenBy(p => p.IsPinned ?? false ? 0 : 1) + .ThenBy(p => p.UserAlias ?? p.UserUID).ToList(); ImGui.Indent(ImGui.GetStyle().ItemSpacing.X / 2); ImGui.Separator(); foreach (var pair in pairsInGroup) { - UiShared.DrawWithID(group.GID + pair.UserUID, () => DrawSyncshellPairedClient(pair, string.Equals(group.OwnedBy, _apiController.UID, StringComparison.Ordinal), group?.IsPaused ?? false)); + UiShared.DrawWithID(group.GID + pair.UserUID, () => DrawSyncshellPairedClient(pair, + string.Equals(group.OwnedBy, _apiController.UID, StringComparison.Ordinal), + group.IsModerator ?? false, + group?.IsPaused ?? false)); } ImGui.Separator(); @@ -290,6 +298,7 @@ namespace MareSynchronos.UI var lockedIcon = invitesEnabled ? FontAwesomeIcon.LockOpen : FontAwesomeIcon.Lock; var iconSize = UiShared.GetIconSize(lockedIcon); var barbuttonSize = UiShared.GetIconButtonSize(FontAwesomeIcon.Bars); + var isOwner = string.Equals(entry.OwnedBy, _apiController.UID, StringComparison.Ordinal); ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiShared.GetWindowContentRegionWidth() - barbuttonSize.X - iconSize.X - ImGui.GetStyle().ItemSpacing.X); ImGui.PushFont(UiBuilder.IconFont); @@ -320,43 +329,46 @@ namespace MareSynchronos.UI } UiShared.AttachToolTip("Copy Syncshell ID to Clipboard"); - if (string.Equals(entry.OwnedBy, _apiController.UID, StringComparison.Ordinal)) + if (isOwner || (entry.IsModerator ?? false)) { ImGui.Separator(); - if (UiShared.IconTextButton(lockedIcon, invitesEnabled ? "Lock Syncshell" : "Unlock Syncshell")) + if (isOwner) { - _ = _apiController.SendGroupChangeInviteState(entry.GID, !entry.InvitesEnabled ?? true); - } - UiShared.AttachToolTip("Change Syncshell joining permissions" + Environment.NewLine + "Syncshell is currently " + (invitesEnabled ? "open" : "closed") + " for people to join"); - - if (UiShared.IconTextButton(FontAwesomeIcon.Passport, "Change Password")) - { - ImGui.OpenPopup("Change Syncshell Password"); - _isPasswordValid = true; - _showModalChangePassword = true; - } - UiShared.AttachToolTip("Change Syncshell Password"); - - if (ImGui.BeginPopupModal("Change Syncshell Password", ref _showModalChangePassword, ImGuiWindowFlags.AlwaysAutoResize)) - { - UiShared.TextWrapped("Enter the new Syncshell password for Syncshell " + name + " here."); - UiShared.TextWrapped("This action is irreversible"); - ImGui.InputTextWithHint("##changepw", "New password for " + name, ref _newSyncShellPassword, 255); - if (ImGui.Button("Change password")) + if (UiShared.IconTextButton(lockedIcon, invitesEnabled ? "Lock Syncshell" : "Unlock Syncshell")) { - var pw = _newSyncShellPassword; - _isPasswordValid = _apiController.ChangeGroupPassword(entry.GID, pw).Result; - _newSyncShellPassword = string.Empty; - if (_isPasswordValid) _showModalChangePassword = false; + _ = _apiController.SendGroupChangeInviteState(entry.GID, !entry.InvitesEnabled ?? true); } + UiShared.AttachToolTip("Change Syncshell joining permissions" + Environment.NewLine + "Syncshell is currently " + (invitesEnabled ? "open" : "closed") + " for people to join"); - if (!_isPasswordValid) + if (UiShared.IconTextButton(FontAwesomeIcon.Passport, "Change Password")) { - UiShared.ColorTextWrapped("The selected password is too short. It must be at least 10 characters.", new Vector4(1, 0, 0, 1)); + ImGui.OpenPopup("Change Syncshell Password"); + _isPasswordValid = true; + _showModalChangePassword = true; } + UiShared.AttachToolTip("Change Syncshell Password"); - ImGui.EndPopup(); + if (ImGui.BeginPopupModal("Change Syncshell Password", ref _showModalChangePassword, ImGuiWindowFlags.AlwaysAutoResize)) + { + UiShared.TextWrapped("Enter the new Syncshell password for Syncshell " + name + " here."); + UiShared.TextWrapped("This action is irreversible"); + ImGui.InputTextWithHint("##changepw", "New password for " + name, ref _newSyncShellPassword, 255); + if (ImGui.Button("Change password")) + { + var pw = _newSyncShellPassword; + _isPasswordValid = _apiController.ChangeGroupPassword(entry.GID, pw).Result; + _newSyncShellPassword = string.Empty; + if (_isPasswordValid) _showModalChangePassword = false; + } + + if (!_isPasswordValid) + { + UiShared.ColorTextWrapped("The selected password is too short. It must be at least 10 characters.", new Vector4(1, 0, 0, 1)); + } + + ImGui.EndPopup(); + } } if (UiShared.IconTextButton(FontAwesomeIcon.Broom, "Clear Syncshell")) @@ -369,21 +381,29 @@ namespace MareSynchronos.UI UiShared.AttachToolTip("Hold CTRL and click to clear this Syncshell." + Environment.NewLine + "WARNING: this action is irreversible." + Environment.NewLine + "Clearing the Syncshell will remove all not pinned users from it."); - if (UiShared.IconTextButton(FontAwesomeIcon.Trash, "Delete Syncshell")) + if (UiShared.IconTextButton(FontAwesomeIcon.Ban, "Manage Banlist")) { - if (UiShared.CtrlPressed() && UiShared.ShiftPressed()) - { - _ = _apiController.SendDeleteGroup(entry.GID); - } + // todo: show banlist + } + + if (isOwner) + { + if (UiShared.IconTextButton(FontAwesomeIcon.Trash, "Delete Syncshell")) + { + if (UiShared.CtrlPressed() && UiShared.ShiftPressed()) + { + _ = _apiController.SendDeleteGroup(entry.GID); + } + } + UiShared.AttachToolTip("Hold CTRL and Shift and click to delete this Syncshell." + Environment.NewLine + "WARNING: this action is irreversible."); } - UiShared.AttachToolTip("Hold CTRL and Shift and click to delete this Syncshell." + Environment.NewLine + "WARNING: this action is irreversible."); } ImGui.EndPopup(); } } - private void DrawSyncshellPairedClient(GroupPairDto entry, bool isOwner, bool isPausedByYou) + private void DrawSyncshellPairedClient(GroupPairDto entry, bool isOwner, bool isModerator, bool isPausedByYou) { var plusButtonSize = UiShared.GetIconButtonSize(FontAwesomeIcon.Plus); var barButtonSize = UiShared.GetIconButtonSize(FontAwesomeIcon.Bars); @@ -411,14 +431,26 @@ namespace MareSynchronos.UI UiShared.AttachToolTip("You are paired with " + entryUID); } - if (entry.IsPinned ?? false) + if (entry.IsModerator ?? false) { ImGui.SameLine(); ImGui.SetCursorPosY(textPos); ImGui.PushFont(UiBuilder.IconFont); - ImGui.TextUnformatted(FontAwesomeIcon.Thumbtack.ToIconString()); + ImGui.TextUnformatted(FontAwesomeIcon.UserShield.ToIconString()); ImGui.PopFont(); - UiShared.AttachToolTip("User is pinned in this Syncshell"); + UiShared.AttachToolTip("User is moderator of this Syncshell"); + } + else + { + if (entry.IsPinned ?? false) + { + ImGui.SameLine(); + ImGui.SetCursorPosY(textPos); + ImGui.PushFont(UiBuilder.IconFont); + ImGui.TextUnformatted(FontAwesomeIcon.Thumbtack.ToIconString()); + ImGui.PopFont(); + UiShared.AttachToolTip("User is pinned in this Syncshell"); + } } var textIsUid = true; @@ -502,7 +534,7 @@ namespace MareSynchronos.UI UiShared.AttachToolTip("Pair with " + entryUID + " individually"); } - if (isOwner) + if (isOwner || isModerator) { ImGui.SetCursorPosY(originalY); var subtractedWidth = plusButtonShown ? (plusButtonSize.X) : 0; @@ -521,14 +553,6 @@ namespace MareSynchronos.UI _ = _apiController.SendChangeUserPinned(entry.GroupGID, entry.UserUID, !entry.IsPinned ?? false); } UiShared.AttachToolTip("Pin this user to the Syncshell. Pinned users will not be deleted in case of a manually initiated Syncshell clean"); - if (UiShared.IconTextButton(FontAwesomeIcon.Crown, "Transfer Ownership")) - { - if (UiShared.CtrlPressed() && UiShared.ShiftPressed()) - { - _ = _apiController.ChangeOwnerOfGroup(entry.GroupGID, entry.UserUID); - } - } - UiShared.AttachToolTip("Hold CTRL and SHIFT and click to transfer ownership of this Syncshell to " + (entry.UserAlias ?? entry.UserUID) + Environment.NewLine + "WARNING: This action is irreversible."); if (UiShared.IconTextButton(FontAwesomeIcon.Trash, "Remove user")) { if (UiShared.CtrlPressed()) @@ -537,6 +561,49 @@ namespace MareSynchronos.UI } } UiShared.AttachToolTip("Hold CTRL and click to remove user " + (entry.UserAlias ?? entry.UserUID) + " from Syncshell"); + if (UiShared.IconTextButton(FontAwesomeIcon.UserSlash, "Ban User")) + { + _showModalBanUser = true; + ImGui.OpenPopup("Ban User"); + } + UiShared.AttachToolTip("Ban user from this Syncshell"); + + if (ImGui.BeginPopupModal("Ban User", ref _showModalBanUser)) + { + ImGui.SetWindowSize(new Vector2(300, 200)); + UiShared.TextWrapped("User " + (entry.UserAlias ?? entry.UserUID) + " will be banned and removed from this Syncshell."); + ImGui.InputTextWithHint("##banreason", "Ban Reason", ref _banReason, 255); + if (ImGui.Button("Ban User")) + { + var reason = _banReason; + _ = _apiController.BanUserFromGroup(entry.GroupGID, entry.UserUID, reason); + _banReason = string.Empty; + } + UiShared.TextWrapped("The reason will be displayed in the banlist. The current server-side alias if present (Vanity ID) will automatically be attached to the reason."); + ImGui.EndPopup(); + } + + if (isOwner) + { + string modText = (entry.IsModerator ?? false) ? "Demod user" : "Mod user"; + if (UiShared.IconTextButton(FontAwesomeIcon.UserShield, modText)) + { + if (UiShared.CtrlPressed()) + { + _ = _apiController.SetModeratorForGroup(entry.GroupGID, entry.UserUID, !entry.IsModerator ?? false); + } + } + UiShared.AttachToolTip("Hold CTRL to change the moderator status for " + (entry.UserAlias ?? entry.UserUID) + Environment.NewLine + + "Moderators can kick, ban/unban, pin/unpin users and clear the Syncshell."); + if (UiShared.IconTextButton(FontAwesomeIcon.Crown, "Transfer Ownership")) + { + if (UiShared.CtrlPressed() && UiShared.ShiftPressed()) + { + _ = _apiController.ChangeOwnerOfGroup(entry.GroupGID, entry.UserUID); + } + } + UiShared.AttachToolTip("Hold CTRL and SHIFT and click to transfer ownership of this Syncshell to " + (entry.UserAlias ?? entry.UserUID) + Environment.NewLine + "WARNING: This action is irreversible."); + } ImGui.EndPopup(); } } diff --git a/MareSynchronos/WebAPI/ApiController.Functions.Callbacks.cs b/MareSynchronos/WebAPI/ApiController.Functions.Callbacks.cs index 04a8da9..7a5edef 100644 --- a/MareSynchronos/WebAPI/ApiController.Functions.Callbacks.cs +++ b/MareSynchronos/WebAPI/ApiController.Functions.Callbacks.cs @@ -95,6 +95,7 @@ public partial class ApiController existingUser.IsPaused = dto.IsPaused ?? existingUser.IsPaused; existingUser.UserAlias = dto.UserAlias ?? existingUser.UserAlias; existingUser.IsPinned = dto.IsPinned ?? existingUser.IsPinned; + existingUser.IsModerator = dto.IsModerator ?? existingUser.IsModerator; } private async Task GroupChangedCallback(GroupDto dto) @@ -117,5 +118,6 @@ public partial class ApiController existingGroup.OwnedBy = dto.OwnedBy ?? existingGroup.OwnedBy; existingGroup.InvitesEnabled = dto.InvitesEnabled ?? existingGroup.InvitesEnabled; existingGroup.IsPaused = dto.IsPaused ?? existingGroup.IsPaused; + existingGroup.IsModerator = dto.IsModerator ?? existingGroup.IsModerator; } } diff --git a/MareSynchronos/WebAPI/ApiController.Functions.Groups.cs b/MareSynchronos/WebAPI/ApiController.Functions.Groups.cs index 2d6e774..4a7fe8c 100644 --- a/MareSynchronos/WebAPI/ApiController.Functions.Groups.cs +++ b/MareSynchronos/WebAPI/ApiController.Functions.Groups.cs @@ -84,4 +84,28 @@ public partial class ApiController if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return; await _mareHub!.SendAsync(Api.SendGroupChangeOwner, gid, uid).ConfigureAwait(false); } + + public async Task BanUserFromGroup(string gid, string uid, string reason) + { + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return; + await _mareHub!.SendAsync(Api.SendBanUserFromGroup, gid, uid, reason).ConfigureAwait(false); + } + + public async Task UnbanUserFromGroup(string gid, string uid) + { + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return; + await _mareHub!.SendAsync(Api.SendUnbanUserFromGroup, gid, uid).ConfigureAwait(false); + } + + public async Task> GetBannedUsersForGroup(string gid) + { + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return new(); + return await _mareHub!.InvokeAsync>(Api.InvokeGetBannedUsersForGroup, gid).ConfigureAwait(false); + } + + public async Task SetModeratorForGroup(string gid, string uid, bool isModerator) + { + if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return; + await _mareHub!.SendAsync(Api.SendAdminChangeModeratorStatus, gid, uid, isModerator).ConfigureAwait(false); + } } \ No newline at end of file