Dalamud branch detection
This commit is contained in:
@@ -10,10 +10,13 @@ internal static class VersionHelper
|
|||||||
|
|
||||||
public static bool IsTesting { get; private set; } = false;
|
public static bool IsTesting { get; private set; } = false;
|
||||||
|
|
||||||
|
public static bool IsDebug { get; private set; } = false;
|
||||||
|
|
||||||
static VersionHelper()
|
static VersionHelper()
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Version = $"{ThisAssembly.Git.Commit}+{ThisAssembly.Git.Sha} [DEBUG]";
|
Version = $"{ThisAssembly.Git.Commit}+{ThisAssembly.Git.Sha} [DEBUG]";
|
||||||
|
IsDebug = true;
|
||||||
#else
|
#else
|
||||||
Version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? string.Empty;
|
Version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? string.Empty;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using CustomizePlus.Configuration.Data;
|
|||||||
using CustomizePlus.Configuration.Services;
|
using CustomizePlus.Configuration.Services;
|
||||||
using CustomizePlus.Core.Events;
|
using CustomizePlus.Core.Events;
|
||||||
using CustomizePlus.Core.Services;
|
using CustomizePlus.Core.Services;
|
||||||
|
using CustomizePlus.Core.Services.Dalamud;
|
||||||
using CustomizePlus.Game.Events;
|
using CustomizePlus.Game.Events;
|
||||||
using CustomizePlus.Game.Services;
|
using CustomizePlus.Game.Services;
|
||||||
using CustomizePlus.Game.Services.GPose;
|
using CustomizePlus.Game.Services.GPose;
|
||||||
@@ -139,7 +140,7 @@ public static class ServiceManagerBuilder
|
|||||||
.AddSingleton<BackupService>()
|
.AddSingleton<BackupService>()
|
||||||
.AddSingleton<FrameworkManager>()
|
.AddSingleton<FrameworkManager>()
|
||||||
.AddSingleton<SupportLogBuilderService>()
|
.AddSingleton<SupportLogBuilderService>()
|
||||||
.AddSingleton<TestingVersionNotifierService>();
|
.AddSingleton<UserNotifierService>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|||||||
51
CustomizePlus/Core/Services/Dalamud/DalamudBranchService.cs
Normal file
51
CustomizePlus/Core/Services/Dalamud/DalamudBranchService.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using OtterGui.Log;
|
||||||
|
using OtterGui.Services;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CustomizePlus.Core.Services.Dalamud;
|
||||||
|
|
||||||
|
public class DalamudBranchService : IService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Current Dalamud branch
|
||||||
|
/// </summary>
|
||||||
|
public DalamudBranch CurrentBranch { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current Dalamud branch name
|
||||||
|
/// </summary>
|
||||||
|
public string CurrentBranchName { get; private set; }
|
||||||
|
|
||||||
|
public DalamudBranchService(DalamudConfigService dalamudConfigService, Logger logger)
|
||||||
|
{
|
||||||
|
dalamudConfigService.GetDalamudConfig<string>(DalamudConfigService.BetaKindOption, out var betaOption);
|
||||||
|
|
||||||
|
CurrentBranchName = betaOption?.ToLowerInvariant() ?? "release";
|
||||||
|
switch (CurrentBranchName)
|
||||||
|
{
|
||||||
|
case "release":
|
||||||
|
CurrentBranch = DalamudBranch.Release;
|
||||||
|
break;
|
||||||
|
case "stg":
|
||||||
|
CurrentBranch = DalamudBranch.Staging;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
CurrentBranch = DalamudBranch.Other;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Information($"Current Dalamud branch is: {CurrentBranchName} ({CurrentBranch})");
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum DalamudBranch
|
||||||
|
{
|
||||||
|
//For our purposes we want to default to Release
|
||||||
|
Release,
|
||||||
|
Staging,
|
||||||
|
Other
|
||||||
|
}
|
||||||
|
}
|
||||||
68
CustomizePlus/Core/Services/Dalamud/DalamudConfigService.cs
Normal file
68
CustomizePlus/Core/Services/Dalamud/DalamudConfigService.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
using Dalamud.Plugin;
|
||||||
|
using OtterGui.Services;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace CustomizePlus.Core.Services.Dalamud;
|
||||||
|
|
||||||
|
public class DalamudConfigService : IService
|
||||||
|
{
|
||||||
|
public DalamudConfigService()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var serviceType =
|
||||||
|
typeof(IDalamudPluginInterface).Assembly.DefinedTypes.FirstOrDefault(t => t.Name == "Service`1" && t.IsGenericType);
|
||||||
|
var configType = typeof(IDalamudPluginInterface).Assembly.DefinedTypes.FirstOrDefault(t => t.Name == "DalamudConfiguration");
|
||||||
|
var interfaceType = typeof(IDalamudPluginInterface).Assembly.DefinedTypes.FirstOrDefault(t => t.Name == "DalamudInterface");
|
||||||
|
if (serviceType == null || configType == null || interfaceType == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var configService = serviceType.MakeGenericType(configType);
|
||||||
|
var interfaceService = serviceType.MakeGenericType(interfaceType);
|
||||||
|
var configGetter = configService.GetMethod("Get", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
_interfaceGetter = interfaceService.GetMethod("Get", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
if (configGetter == null || _interfaceGetter == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_dalamudConfig = configGetter.Invoke(null, null);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
_dalamudConfig = null;
|
||||||
|
_interfaceGetter = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public const string BetaKindOption = "DalamudBetaKind";
|
||||||
|
|
||||||
|
private readonly object? _dalamudConfig;
|
||||||
|
private readonly MethodInfo? _interfaceGetter;
|
||||||
|
|
||||||
|
public bool GetDalamudConfig<T>(string fieldName, out T? value)
|
||||||
|
{
|
||||||
|
value = default;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_dalamudConfig == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var getter = _dalamudConfig.GetType().GetProperty(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
if (getter == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var result = getter.GetValue(_dalamudConfig);
|
||||||
|
if (result is not T v)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
value = v;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Plugin.Logger.Error($"Error while fetching Dalamud Config {fieldName}:\n{e}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ using Dalamud.Plugin.Services;
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using OtterGui.Services;
|
using OtterGui.Services;
|
||||||
|
|
||||||
namespace CustomizePlus.Core.Services;
|
namespace CustomizePlus.Core.Services.Dalamud;
|
||||||
|
|
||||||
public class DalamudServices
|
public class DalamudServices
|
||||||
{
|
{
|
||||||
@@ -13,6 +13,7 @@ using CustomizePlus.GameData.Data;
|
|||||||
using Penumbra.GameData.Interop;
|
using Penumbra.GameData.Interop;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using CustomizePlus.Core.Helpers;
|
using CustomizePlus.Core.Helpers;
|
||||||
|
using CustomizePlus.Core.Services.Dalamud;
|
||||||
|
|
||||||
namespace CustomizePlus.Core.Services;
|
namespace CustomizePlus.Core.Services;
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@ public class HookingService : IDisposable
|
|||||||
private readonly ProfileManager _profileManager;
|
private readonly ProfileManager _profileManager;
|
||||||
private readonly ArmatureManager _armatureManager;
|
private readonly ArmatureManager _armatureManager;
|
||||||
private readonly GameStateService _gameStateService;
|
private readonly GameStateService _gameStateService;
|
||||||
|
//private readonly DalamudBranchService _dalamudBranchService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
private Hook<RenderDelegate>? _renderManagerHook;
|
private Hook<RenderDelegate>? _renderManagerHook;
|
||||||
@@ -44,6 +46,7 @@ public class HookingService : IDisposable
|
|||||||
ProfileManager profileManager,
|
ProfileManager profileManager,
|
||||||
ArmatureManager armatureManager,
|
ArmatureManager armatureManager,
|
||||||
GameStateService gameStateService,
|
GameStateService gameStateService,
|
||||||
|
//DalamudBranchService dalamudBranchService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
{
|
{
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
@@ -52,6 +55,7 @@ public class HookingService : IDisposable
|
|||||||
_profileManager = profileManager;
|
_profileManager = profileManager;
|
||||||
_armatureManager = armatureManager;
|
_armatureManager = armatureManager;
|
||||||
_gameStateService = gameStateService;
|
_gameStateService = gameStateService;
|
||||||
|
//_dalamudBranchService = dalamudBranchService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
ReloadHooks();
|
ReloadHooks();
|
||||||
@@ -71,6 +75,9 @@ public class HookingService : IDisposable
|
|||||||
RenderHookFailed = false;
|
RenderHookFailed = false;
|
||||||
MovementHookFailed = false;
|
MovementHookFailed = false;
|
||||||
|
|
||||||
|
/*if(_dalamudBranchService.CurrentBranch != DalamudBranchService.DalamudBranch.Release)
|
||||||
|
return;*/
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_configuration.PluginEnabled)
|
if (_configuration.PluginEnabled)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using CustomizePlus.Configuration.Data;
|
|||||||
using CustomizePlus.Core.Data;
|
using CustomizePlus.Core.Data;
|
||||||
using CustomizePlus.Core.Extensions;
|
using CustomizePlus.Core.Extensions;
|
||||||
using CustomizePlus.Core.Helpers;
|
using CustomizePlus.Core.Helpers;
|
||||||
|
using CustomizePlus.Core.Services.Dalamud;
|
||||||
using CustomizePlus.Profiles;
|
using CustomizePlus.Profiles;
|
||||||
using CustomizePlus.Templates;
|
using CustomizePlus.Templates;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
@@ -20,19 +21,22 @@ public class SupportLogBuilderService
|
|||||||
private readonly ProfileManager _profileManager;
|
private readonly ProfileManager _profileManager;
|
||||||
private readonly ArmatureManager _armatureManager;
|
private readonly ArmatureManager _armatureManager;
|
||||||
private readonly IDalamudPluginInterface _dalamudPluginInterface;
|
private readonly IDalamudPluginInterface _dalamudPluginInterface;
|
||||||
|
private readonly DalamudBranchService _dalamudBranchService;
|
||||||
|
|
||||||
public SupportLogBuilderService(
|
public SupportLogBuilderService(
|
||||||
PluginConfiguration configuration,
|
PluginConfiguration configuration,
|
||||||
TemplateManager templateManager,
|
TemplateManager templateManager,
|
||||||
ProfileManager profileManager,
|
ProfileManager profileManager,
|
||||||
ArmatureManager armatureManager,
|
ArmatureManager armatureManager,
|
||||||
IDalamudPluginInterface dalamudPluginInterface)
|
IDalamudPluginInterface dalamudPluginInterface,
|
||||||
|
DalamudBranchService dalamudBranchService)
|
||||||
{
|
{
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_templateManager = templateManager;
|
_templateManager = templateManager;
|
||||||
_profileManager = profileManager;
|
_profileManager = profileManager;
|
||||||
_armatureManager = armatureManager;
|
_armatureManager = armatureManager;
|
||||||
_dalamudPluginInterface = dalamudPluginInterface;
|
_dalamudPluginInterface = dalamudPluginInterface;
|
||||||
|
_dalamudBranchService = dalamudBranchService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string BuildSupportLog()
|
public string BuildSupportLog()
|
||||||
@@ -41,6 +45,7 @@ public class SupportLogBuilderService
|
|||||||
sb.AppendLine("**Settings**");
|
sb.AppendLine("**Settings**");
|
||||||
sb.Append($"> **`Plugin Version: `** {VersionHelper.Version}\n");
|
sb.Append($"> **`Plugin Version: `** {VersionHelper.Version}\n");
|
||||||
sb.Append($"> **`Commit Hash: `** {ThisAssembly.Git.Commit}+{ThisAssembly.Git.Sha}\n");
|
sb.Append($"> **`Commit Hash: `** {ThisAssembly.Git.Commit}+{ThisAssembly.Git.Sha}\n");
|
||||||
|
sb.Append($"> **`Dalamud Branch: `** {_dalamudBranchService.CurrentBranchName} ({_dalamudBranchService.CurrentBranch})\n");
|
||||||
sb.Append($"> **`Plugin enabled: `** {_configuration.PluginEnabled}\n");
|
sb.Append($"> **`Plugin enabled: `** {_configuration.PluginEnabled}\n");
|
||||||
sb.AppendLine("**Settings -> Editor Settings**");
|
sb.AppendLine("**Settings -> Editor Settings**");
|
||||||
sb.Append($"> **`Preview character (editor): `** {_configuration.EditorConfiguration.PreviewCharacter.Incognito(null)}\n");
|
sb.Append($"> **`Preview character (editor): `** {_configuration.EditorConfiguration.PreviewCharacter.Incognito(null)}\n");
|
||||||
|
|||||||
@@ -1,19 +1,27 @@
|
|||||||
using System;
|
using System;
|
||||||
using CustomizePlus.Core.Helpers;
|
using CustomizePlus.Core.Helpers;
|
||||||
|
using CustomizePlus.Core.Services.Dalamud;
|
||||||
using CustomizePlus.Game.Services;
|
using CustomizePlus.Game.Services;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
|
|
||||||
namespace CustomizePlus.Core.Services;
|
namespace CustomizePlus.Core.Services;
|
||||||
|
|
||||||
public class TestingVersionNotifierService : IDisposable
|
public class UserNotifierService : IDisposable
|
||||||
{
|
{
|
||||||
private readonly IClientState _clientState;
|
private readonly IClientState _clientState;
|
||||||
private readonly ChatService _chatService;
|
private readonly ChatService _chatService;
|
||||||
|
private readonly DalamudBranchService _dalamudBranchService;
|
||||||
|
|
||||||
public TestingVersionNotifierService(IClientState clientState, ChatService chatService)
|
public UserNotifierService(
|
||||||
|
IClientState clientState,
|
||||||
|
ChatService chatService,
|
||||||
|
DalamudBranchService dalamudBranchService)
|
||||||
{
|
{
|
||||||
_clientState = clientState;
|
_clientState = clientState;
|
||||||
_chatService = chatService;
|
_chatService = chatService;
|
||||||
|
_dalamudBranchService = dalamudBranchService;
|
||||||
|
|
||||||
|
OnLogin();
|
||||||
|
|
||||||
_clientState.Login += OnLogin;
|
_clientState.Login += OnLogin;
|
||||||
}
|
}
|
||||||
@@ -28,5 +36,9 @@ public class TestingVersionNotifierService : IDisposable
|
|||||||
if (VersionHelper.IsTesting)
|
if (VersionHelper.IsTesting)
|
||||||
_chatService.PrintInChat($"You are running testing version of Customize+! Some features like integration with other plugins might not function correctly.",
|
_chatService.PrintInChat($"You are running testing version of Customize+! Some features like integration with other plugins might not function correctly.",
|
||||||
ChatService.ChatMessageColor.Warning);
|
ChatService.ChatMessageColor.Warning);
|
||||||
|
|
||||||
|
if (_dalamudBranchService.CurrentBranch != DalamudBranchService.DalamudBranch.Release)
|
||||||
|
_chatService.PrintInChat($"You are running development or testing version of Dalamud. This is not supported and might be actively prevented in the future.",
|
||||||
|
ChatService.ChatMessageColor.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
|
|
||||||
_services.GetService<ActorManager>(); //needs to be initialized early for config to be read properly
|
_services.GetService<ActorManager>(); //needs to be initialized early for config to be read properly
|
||||||
|
|
||||||
_services.GetService<TestingVersionNotifierService>();
|
_services.GetService<UserNotifierService>();
|
||||||
_services.GetService<CustomizePlusIpc>();
|
_services.GetService<CustomizePlusIpc>();
|
||||||
_services.GetService<CPlusWindowSystem>();
|
_services.GetService<CPlusWindowSystem>();
|
||||||
_services.GetService<CommandService>();
|
_services.GetService<CommandService>();
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using CustomizePlus.UI.Windows.MainWindow.Tabs.Templates;
|
|||||||
using CustomizePlus.Core.Helpers;
|
using CustomizePlus.Core.Helpers;
|
||||||
using CustomizePlus.Api;
|
using CustomizePlus.Api;
|
||||||
using CustomizePlus.Core.Data;
|
using CustomizePlus.Core.Data;
|
||||||
|
using CustomizePlus.Core.Services.Dalamud;
|
||||||
|
|
||||||
namespace CustomizePlus.UI.Windows.Controls;
|
namespace CustomizePlus.UI.Windows.Controls;
|
||||||
|
|
||||||
@@ -19,19 +20,22 @@ public class PluginStateBlock
|
|||||||
private readonly GameStateService _gameStateService;
|
private readonly GameStateService _gameStateService;
|
||||||
private readonly HookingService _hookingService;
|
private readonly HookingService _hookingService;
|
||||||
private readonly CustomizePlusIpc _ipcService;
|
private readonly CustomizePlusIpc _ipcService;
|
||||||
|
private readonly DalamudBranchService _dalamudBranchService;
|
||||||
|
|
||||||
public PluginStateBlock(
|
public PluginStateBlock(
|
||||||
BoneEditorPanel boneEditorPanel,
|
BoneEditorPanel boneEditorPanel,
|
||||||
PluginConfiguration configuration,
|
PluginConfiguration configuration,
|
||||||
GameStateService gameStateService,
|
GameStateService gameStateService,
|
||||||
HookingService hookingService,
|
HookingService hookingService,
|
||||||
CustomizePlusIpc ipcService)
|
CustomizePlusIpc ipcService,
|
||||||
|
DalamudBranchService dalamudBranchService)
|
||||||
{
|
{
|
||||||
_boneEditorPanel = boneEditorPanel;
|
_boneEditorPanel = boneEditorPanel;
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_gameStateService = gameStateService;
|
_gameStateService = gameStateService;
|
||||||
_hookingService = hookingService;
|
_hookingService = hookingService;
|
||||||
_ipcService = ipcService;
|
_ipcService = ipcService;
|
||||||
|
_dalamudBranchService = dalamudBranchService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Draw(float yPos)
|
public void Draw(float yPos)
|
||||||
@@ -43,7 +47,7 @@ public class PluginStateBlock
|
|||||||
if(_hookingService.RenderHookFailed || _hookingService.MovementHookFailed)
|
if(_hookingService.RenderHookFailed || _hookingService.MovementHookFailed)
|
||||||
{
|
{
|
||||||
severity = PluginStateSeverity.Error;
|
severity = PluginStateSeverity.Error;
|
||||||
message = $"Detected failure in game hooks. Customize+ disabled.";
|
message = "Detected failure in game hooks. Customize+ disabled.";
|
||||||
}
|
}
|
||||||
else if (!_configuration.PluginEnabled)
|
else if (!_configuration.PluginEnabled)
|
||||||
{
|
{
|
||||||
@@ -68,17 +72,23 @@ public class PluginStateBlock
|
|||||||
else if (_gameStateService.GameInPosingMode())
|
else if (_gameStateService.GameInPosingMode())
|
||||||
{
|
{
|
||||||
severity = PluginStateSeverity.Warning;
|
severity = PluginStateSeverity.Warning;
|
||||||
message = $"GPose active. Compatibility with posing tools is limited.";
|
message = "GPose active. Compatibility with posing tools is limited.";
|
||||||
}
|
}
|
||||||
else if (_ipcService.IPCFailed) //this is a low priority error
|
else if (_ipcService.IPCFailed) //this is a low priority error
|
||||||
{
|
{
|
||||||
severity = PluginStateSeverity.Error;
|
severity = PluginStateSeverity.Error;
|
||||||
message = $"Detected failure in IPC. Integrations with other plugins will not function.";
|
message = "Detected failure in IPC. Integrations with other plugins will not function.";
|
||||||
|
}
|
||||||
|
else if (_dalamudBranchService.CurrentBranch != DalamudBranchService.DalamudBranch.Release)
|
||||||
|
{
|
||||||
|
severity = PluginStateSeverity.Error;
|
||||||
|
message = "You are running unsupported version of Dalamud, hover for more information.";
|
||||||
|
hoverInfo = "Regular users are not supposed to run Customize+ on development or testing versions of Dalamud.\nThis is not supported and might be actively prevented in the future.";
|
||||||
}
|
}
|
||||||
else if(VersionHelper.IsTesting)
|
else if(VersionHelper.IsTesting)
|
||||||
{
|
{
|
||||||
severity = PluginStateSeverity.Warning;
|
severity = PluginStateSeverity.Warning;
|
||||||
message = $"You are running testing version of Customize+, hover for more information.";
|
message = "You are running testing version of Customize+, hover for more information.";
|
||||||
hoverInfo = "This is a testing build of Customize+. Some features like integration with other plugins might not function correctly.";
|
hoverInfo = "This is a testing build of Customize+. Some features like integration with other plugins might not function correctly.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user