Add login/profile display to the main menu.
This commit is contained in:
@@ -917,6 +917,7 @@
|
||||
<Compile Include="ModCredits.cs" />
|
||||
<Compile Include="Lint\CheckUnknownTraitFields.cs" />
|
||||
<Compile Include="Lint\CheckUnknownWeaponFields.cs" />
|
||||
<Compile Include="Widgets\Logic\PlayerProfileLogic.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="AfterBuild">
|
||||
|
||||
@@ -228,6 +228,16 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
menuType != MenuType.SystemInfoPrompt &&
|
||||
webServices.ModVersionStatus == ModVersionStatus.Outdated;
|
||||
|
||||
var playerProfile = widget.GetOrNull("PLAYER_PROFILE_CONTAINER");
|
||||
if (playerProfile != null)
|
||||
{
|
||||
Func<bool> minimalProfile = () => Ui.CurrentWindow() != null;
|
||||
Game.LoadWidget(world, "LOCAL_PROFILE_PANEL", playerProfile, new WidgetArgs()
|
||||
{
|
||||
{ "minimalProfile", minimalProfile }
|
||||
});
|
||||
}
|
||||
|
||||
// System information opt-out prompt
|
||||
var sysInfoPrompt = widget.Get("SYSTEM_INFO_PROMPT");
|
||||
sysInfoPrompt.IsVisible = () => menuType == MenuType.SystemInfoPrompt;
|
||||
|
||||
91
OpenRA.Mods.Common/Widgets/Logic/PlayerProfileLogic.cs
Normal file
91
OpenRA.Mods.Common/Widgets/Logic/PlayerProfileLogic.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2018 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
public class LocalProfileLogic : ChromeLogic
|
||||
{
|
||||
readonly LocalPlayerProfile localProfile;
|
||||
readonly Widget detailsContainer;
|
||||
bool notFound;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public LocalProfileLogic(Widget widget, WorldRenderer worldRenderer, Func<bool> minimalProfile)
|
||||
{
|
||||
localProfile = Game.LocalPlayerProfile;
|
||||
|
||||
// Key registration
|
||||
widget.Get("GENERATE_KEYS").IsVisible = () => localProfile.State == LocalPlayerProfile.LinkState.Uninitialized && !minimalProfile();
|
||||
widget.Get("GENERATING_KEYS").IsVisible = () => localProfile.State == LocalPlayerProfile.LinkState.GeneratingKeys && !minimalProfile();
|
||||
|
||||
var lastProfileState = LocalPlayerProfile.LinkState.CheckingLink;
|
||||
widget.Get("REGISTER_FINGERPRINT").IsVisible = () =>
|
||||
{
|
||||
// Take a copy of the state to avoid race conditions
|
||||
var state = localProfile.State;
|
||||
|
||||
// Copy the key to the clipboard when displaying the link instructions
|
||||
if (state != lastProfileState && state == LocalPlayerProfile.LinkState.Unlinked)
|
||||
Game.SetClipboardText(localProfile.PublicKey);
|
||||
|
||||
lastProfileState = state;
|
||||
return localProfile.State == LocalPlayerProfile.LinkState.Unlinked && !notFound && !minimalProfile();
|
||||
};
|
||||
|
||||
widget.Get("CHECKING_FINGERPRINT").IsVisible = () => localProfile.State == LocalPlayerProfile.LinkState.CheckingLink && !minimalProfile();
|
||||
widget.Get("FINGERPRINT_NOT_FOUND").IsVisible = () => localProfile.State == LocalPlayerProfile.LinkState.Unlinked && notFound && !minimalProfile();
|
||||
widget.Get("CONNECTION_ERROR").IsVisible = () => localProfile.State == LocalPlayerProfile.LinkState.ConnectionFailed && !minimalProfile();
|
||||
|
||||
widget.Get<ButtonWidget>("GENERATE_KEY").OnClick = localProfile.GenerateKeypair;
|
||||
|
||||
widget.Get<ButtonWidget>("CHECK_KEY").OnClick = () => localProfile.RefreshPlayerData(() => RefreshComplete(true));
|
||||
|
||||
widget.Get<ButtonWidget>("DELETE_KEY").OnClick = () =>
|
||||
{
|
||||
localProfile.DeleteKeypair();
|
||||
Game.RunAfterTick(Ui.ResetTooltips);
|
||||
};
|
||||
|
||||
widget.Get<ButtonWidget>("FINGERPRINT_NOT_FOUND_CONTINUE").OnClick = () =>
|
||||
{
|
||||
notFound = false;
|
||||
Game.RunAfterTick(Ui.ResetTooltips);
|
||||
};
|
||||
|
||||
widget.Get<ButtonWidget>("CONNECTION_ERROR_RETRY").OnClick = () => localProfile.RefreshPlayerData(() => RefreshComplete(true));
|
||||
|
||||
// Profile view
|
||||
widget.Get("PROFILE_HEADER").IsVisible = () => localProfile.State == LocalPlayerProfile.LinkState.Linked;
|
||||
widget.Get<LabelWidget>("PROFILE_NAME").GetText = () => localProfile.ProfileData.ProfileName;
|
||||
widget.Get<LabelWidget>("PROFILE_RANK").GetText = () => localProfile.ProfileData.ProfileRank;
|
||||
|
||||
var destroyKey = widget.Get<ButtonWidget>("DESTROY_KEY");
|
||||
destroyKey.OnClick = localProfile.DeleteKeypair;
|
||||
destroyKey.IsDisabled = minimalProfile;
|
||||
|
||||
detailsContainer = widget.Get("PROFILE_DETAILS");
|
||||
detailsContainer.IsVisible = () => localProfile.State == LocalPlayerProfile.LinkState.Linked && !minimalProfile();
|
||||
localProfile.RefreshPlayerData(() => RefreshComplete(false));
|
||||
}
|
||||
|
||||
public void RefreshComplete(bool updateNotFound)
|
||||
{
|
||||
if (updateNotFound)
|
||||
notFound = localProfile.State == LocalPlayerProfile.LinkState.Unlinked;
|
||||
|
||||
Game.RunAfterTick(Ui.ResetTooltips);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -320,3 +320,6 @@ Container@MENU_BACKGROUND:
|
||||
Y: 10
|
||||
Width: 200
|
||||
Height: 200
|
||||
Container@PLAYER_PROFILE_CONTAINER:
|
||||
X: 31
|
||||
Y: 31
|
||||
|
||||
210
mods/cnc/chrome/playerprofile.yaml
Normal file
210
mods/cnc/chrome/playerprofile.yaml
Normal file
@@ -0,0 +1,210 @@
|
||||
Container@LOCAL_PROFILE_PANEL:
|
||||
Logic: LocalProfileLogic
|
||||
Width: 270
|
||||
Height: 100
|
||||
Children:
|
||||
Background@PROFILE_HEADER:
|
||||
Width: PARENT_RIGHT
|
||||
Height: 50
|
||||
Background: panel-black
|
||||
Children:
|
||||
Label@PROFILE_NAME:
|
||||
X: 10
|
||||
Y: 3
|
||||
Width: PARENT_RIGHT - 20
|
||||
Height: 25
|
||||
Font: MediumBold
|
||||
Label@PROFILE_RANK:
|
||||
X: 10
|
||||
Y: 23
|
||||
Width: PARENT_RIGHT - 20
|
||||
Height: 25
|
||||
Font: TinyBold
|
||||
Button@DESTROY_KEY:
|
||||
X: PARENT_RIGHT - 70
|
||||
Y: 15
|
||||
Width: 60
|
||||
Height: 20
|
||||
Font: TinyBold
|
||||
BaseLine: 1
|
||||
Text: Logout
|
||||
Background@GENERATE_KEYS:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
Background: panel-black
|
||||
Children:
|
||||
Label@DESC_A:
|
||||
Y: 5
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: Connect to a forum account to identify
|
||||
Label@DESC_B:
|
||||
Y: 21
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: yourself to other players, join private
|
||||
Label@DESC_C:
|
||||
Y: 37
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: servers, and display badges.
|
||||
Button@GENERATE_KEY:
|
||||
X: (PARENT_RIGHT - WIDTH) / 2
|
||||
Y: 70
|
||||
Width: 240
|
||||
Height: 20
|
||||
Font: TinyBold
|
||||
BaseLine: 1
|
||||
Text: Connect to an OpenRA forum account
|
||||
Background@GENERATING_KEYS:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
Background: panel-black
|
||||
Children:
|
||||
Label@DESC_A:
|
||||
Y: 13
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: Generating authentication key pair.
|
||||
Label@DESC_B:
|
||||
Y: 29
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: This will take several seconds...
|
||||
ProgressBar:
|
||||
X: (PARENT_RIGHT - WIDTH) / 2
|
||||
Y: 70
|
||||
Width: 240
|
||||
Height: 20
|
||||
Indeterminate: true
|
||||
Background@REGISTER_FINGERPRINT:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
Background: panel-black
|
||||
Children:
|
||||
Label@DESC_A:
|
||||
Y: 2
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: An authentication key has been copied to your
|
||||
Label@DESC_B:
|
||||
Y: 18
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: clipboard. Add this to your User Control Panel
|
||||
Label@DESC_C:
|
||||
Y: 34
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: on the OpenRA forum then press Continue.
|
||||
Button@DELETE_KEY:
|
||||
X: 15
|
||||
Y: 70
|
||||
Width: 70
|
||||
Height: 20
|
||||
BaseLine: 1
|
||||
Font: TinyBold
|
||||
Text: Cancel
|
||||
Button@CHECK_KEY:
|
||||
X: 185
|
||||
Y: 70
|
||||
Width: 70
|
||||
Height: 20
|
||||
BaseLine: 1
|
||||
Font: TinyBold
|
||||
Text: Continue
|
||||
Background@CHECKING_FINGERPRINT:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
Background: panel-black
|
||||
Children:
|
||||
Label@DESC_A:
|
||||
Y: 13
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: Querying account details from
|
||||
Label@DESC_B:
|
||||
Y: 29
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: the OpenRA forum...
|
||||
ProgressBar:
|
||||
X: (PARENT_RIGHT - WIDTH) / 2
|
||||
Y: 70
|
||||
Width: 240
|
||||
Height: 20
|
||||
Indeterminate: true
|
||||
Background@FINGERPRINT_NOT_FOUND:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
Background: panel-black
|
||||
Children:
|
||||
Label@DESC_A:
|
||||
Y: 13
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: Your authentication key is not connected
|
||||
Label@DESC_B:
|
||||
Y: 29
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: to an OpenRA forum account.
|
||||
Button@FINGERPRINT_NOT_FOUND_CONTINUE:
|
||||
X: 185
|
||||
Y: 70
|
||||
Width: 70
|
||||
Height: 20
|
||||
BaseLine: 1
|
||||
Font: TinyBold
|
||||
Text: Back
|
||||
Background@CONNECTION_ERROR:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
Background: panel-black
|
||||
Children:
|
||||
Label@DESC_A:
|
||||
Y: 13
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: Failed to connect to the OpenRA forum.
|
||||
Label@DESC_B:
|
||||
Y: 29
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: Please check your internet connection.
|
||||
Button@CONNECTION_ERROR_RETRY:
|
||||
X: 185
|
||||
Y: 70
|
||||
Width: 70
|
||||
Height: 20
|
||||
BaseLine: 1
|
||||
Font: TinyBold
|
||||
Text: Retry
|
||||
@@ -91,6 +91,7 @@ Assemblies:
|
||||
|
||||
ChromeLayout:
|
||||
cnc|chrome/mainmenu.yaml
|
||||
cnc|chrome/playerprofile.yaml
|
||||
cnc|chrome/multiplayer-browser.yaml
|
||||
cnc|chrome/multiplayer-browserpanels.yaml
|
||||
cnc|chrome/multiplayer-createserver.yaml
|
||||
|
||||
@@ -320,3 +320,6 @@ Container@MAINMENU:
|
||||
Align: Center
|
||||
Shadow: true
|
||||
Text: Download the latest version from www.openra.net
|
||||
Container@PLAYER_PROFILE_CONTAINER:
|
||||
X: 25
|
||||
Y: 25
|
||||
|
||||
210
mods/common/chrome/playerprofile.yaml
Normal file
210
mods/common/chrome/playerprofile.yaml
Normal file
@@ -0,0 +1,210 @@
|
||||
Container@LOCAL_PROFILE_PANEL:
|
||||
Logic: LocalProfileLogic
|
||||
Width: 270
|
||||
Height: 100
|
||||
Children:
|
||||
Background@PROFILE_HEADER:
|
||||
Width: PARENT_RIGHT
|
||||
Height: 50
|
||||
Background: dialog2
|
||||
Children:
|
||||
Label@PROFILE_NAME:
|
||||
X: 10
|
||||
Y: 3
|
||||
Width: PARENT_RIGHT - 20
|
||||
Height: 25
|
||||
Font: MediumBold
|
||||
Label@PROFILE_RANK:
|
||||
X: 10
|
||||
Y: 23
|
||||
Width: PARENT_RIGHT - 20
|
||||
Height: 25
|
||||
Font: TinyBold
|
||||
Button@DESTROY_KEY:
|
||||
X: PARENT_RIGHT - 70
|
||||
Y: 15
|
||||
Width: 60
|
||||
Height: 20
|
||||
Font: TinyBold
|
||||
BaseLine: 1
|
||||
Text: Logout
|
||||
Background@GENERATE_KEYS:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
Background: dialog2
|
||||
Children:
|
||||
Label@DESC_A:
|
||||
Y: 5
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: Connect to a forum account to identify
|
||||
Label@DESC_B:
|
||||
Y: 21
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: yourself to other players, join private
|
||||
Label@DESC_C:
|
||||
Y: 37
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: servers, and display badges.
|
||||
Button@GENERATE_KEY:
|
||||
X: (PARENT_RIGHT - WIDTH) / 2
|
||||
Y: 70
|
||||
Width: 240
|
||||
Height: 20
|
||||
Font: TinyBold
|
||||
BaseLine: 1
|
||||
Text: Connect to an OpenRA forum account
|
||||
Background@GENERATING_KEYS:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
Background: dialog2
|
||||
Children:
|
||||
Label@DESC_A:
|
||||
Y: 13
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: Generating authentication key pair.
|
||||
Label@DESC_B:
|
||||
Y: 29
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: This will take several seconds...
|
||||
ProgressBar:
|
||||
X: (PARENT_RIGHT - WIDTH) / 2
|
||||
Y: 70
|
||||
Width: 240
|
||||
Height: 20
|
||||
Indeterminate: true
|
||||
Background@REGISTER_FINGERPRINT:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
Background: dialog2
|
||||
Children:
|
||||
Label@DESC_A:
|
||||
Y: 2
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: An authentication key has been copied to your
|
||||
Label@DESC_B:
|
||||
Y: 18
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: clipboard. Add this to your User Control Panel
|
||||
Label@DESC_C:
|
||||
Y: 34
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: on the OpenRA forum then press Continue.
|
||||
Button@DELETE_KEY:
|
||||
X: 15
|
||||
Y: 70
|
||||
Width: 70
|
||||
Height: 20
|
||||
BaseLine: 1
|
||||
Font: TinyBold
|
||||
Text: Cancel
|
||||
Button@CHECK_KEY:
|
||||
X: 185
|
||||
Y: 70
|
||||
Width: 70
|
||||
Height: 20
|
||||
BaseLine: 1
|
||||
Font: TinyBold
|
||||
Text: Continue
|
||||
Background@CHECKING_FINGERPRINT:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
Background: dialog2
|
||||
Children:
|
||||
Label@DESC_A:
|
||||
Y: 13
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: Querying account details from
|
||||
Label@DESC_B:
|
||||
Y: 29
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: the OpenRA forum...
|
||||
ProgressBar:
|
||||
X: (PARENT_RIGHT - WIDTH) / 2
|
||||
Y: 70
|
||||
Width: 240
|
||||
Height: 20
|
||||
Indeterminate: true
|
||||
Background@FINGERPRINT_NOT_FOUND:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
Background: dialog2
|
||||
Children:
|
||||
Label@DESC_A:
|
||||
Y: 13
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: Your authentication key is not connected
|
||||
Label@DESC_B:
|
||||
Y: 29
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: to an OpenRA forum account.
|
||||
Button@FINGERPRINT_NOT_FOUND_CONTINUE:
|
||||
X: 185
|
||||
Y: 70
|
||||
Width: 70
|
||||
Height: 20
|
||||
BaseLine: 1
|
||||
Font: TinyBold
|
||||
Text: Back
|
||||
Background@CONNECTION_ERROR:
|
||||
Width: PARENT_RIGHT
|
||||
Height: PARENT_BOTTOM
|
||||
Background: dialog2
|
||||
Children:
|
||||
Label@DESC_A:
|
||||
Y: 13
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: Failed to connect to the OpenRA forum.
|
||||
Label@DESC_B:
|
||||
Y: 29
|
||||
Width: PARENT_RIGHT
|
||||
Height: 25
|
||||
Font: Small
|
||||
Align: Center
|
||||
Text: Please check your internet connection.
|
||||
Button@CONNECTION_ERROR_RETRY:
|
||||
X: 185
|
||||
Y: 70
|
||||
Width: 70
|
||||
Height: 20
|
||||
BaseLine: 1
|
||||
Font: TinyBold
|
||||
Text: Retry
|
||||
@@ -306,3 +306,6 @@ Container@MAINMENU:
|
||||
Y: 5
|
||||
Width: 200
|
||||
Height: 200
|
||||
Container@PLAYER_PROFILE_CONTAINER:
|
||||
X: 5
|
||||
Y: 5
|
||||
|
||||
@@ -86,6 +86,7 @@ ChromeLayout:
|
||||
common|chrome/credits.yaml
|
||||
common|chrome/lobby.yaml
|
||||
common|chrome/lobby-mappreview.yaml
|
||||
common|chrome/playerprofile.yaml
|
||||
d2k|chrome/lobby-players.yaml
|
||||
common|chrome/lobby-options.yaml
|
||||
common|chrome/lobby-music.yaml
|
||||
|
||||
@@ -121,6 +121,7 @@ ChromeLayout:
|
||||
common|chrome/missionbrowser.yaml
|
||||
common|chrome/confirmation-dialogs.yaml
|
||||
common|chrome/editor.yaml
|
||||
common|chrome/playerprofile.yaml
|
||||
|
||||
Weapons:
|
||||
ra|weapons/explosions.yaml
|
||||
|
||||
@@ -154,6 +154,7 @@ ChromeLayout:
|
||||
common|chrome/lobby-music.yaml
|
||||
common|chrome/lobby-servers.yaml
|
||||
common|chrome/lobby-kickdialogs.yaml
|
||||
common|chrome/playerprofile.yaml
|
||||
ts|chrome/color-picker.yaml
|
||||
common|chrome/map-chooser.yaml
|
||||
common|chrome/multiplayer-browser.yaml
|
||||
|
||||
Reference in New Issue
Block a user