* Re-implementing console log colors.
* Removed unused code in Log.cpp. --HG-- branch : trunk
This commit is contained in:
@@ -215,7 +215,7 @@ AddonChannel = 1
|
|||||||
#
|
#
|
||||||
# LogLevel
|
# LogLevel
|
||||||
# Server console level of logging
|
# Server console level of logging
|
||||||
# 0 = Minimum; 1 = Basic&Error; 2 = Detail; 3 = Full/Debug
|
# 0 = Minimum; 1 = Basic; 2 = Detail; 3 = Full/Debug
|
||||||
# Default: 3
|
# Default: 3
|
||||||
#
|
#
|
||||||
# LogFile
|
# LogFile
|
||||||
@@ -230,7 +230,7 @@ AddonChannel = 1
|
|||||||
#
|
#
|
||||||
# LogFileLevel
|
# LogFileLevel
|
||||||
# Server file level of logging
|
# Server file level of logging
|
||||||
# 0 = Minimum; 1 = Error; 2 = Detail; 3 = Full/Debug
|
# 0 = Minimum; 1 = Basic; 2 = Detail; 3 = Full/Debug
|
||||||
# Default: 0
|
# Default: 0
|
||||||
#
|
#
|
||||||
# LogFilter_AchievementUpdates
|
# LogFilter_AchievementUpdates
|
||||||
@@ -288,6 +288,13 @@ AddonChannel = 1
|
|||||||
# Default: "Ra.log"
|
# Default: "Ra.log"
|
||||||
# "" - Empty name for disable
|
# "" - Empty name for disable
|
||||||
#
|
#
|
||||||
|
# LogColors
|
||||||
|
# Color for messages (format "normal error basic detail debug")
|
||||||
|
# Colors: 0 - BLACK, 1 - RED, 2 - GREEN, 3 - BROWN, 4 - BLUE, 5 - MAGENTA, 6 - CYAN, 7 - GREY,
|
||||||
|
# 8 - YELLOW, 9 - LRED, 10 - LGREEN, 11 - LBLUE, 12 - LMAGENTA, 13 - LCYAN, 14 - WHITE
|
||||||
|
# Default: "" - none colors
|
||||||
|
# Example: "13 7 11 9 5"
|
||||||
|
#
|
||||||
# EnableLogDB
|
# EnableLogDB
|
||||||
# Enable/disable logging to database (LogDatabaseInfo).
|
# Enable/disable logging to database (LogDatabaseInfo).
|
||||||
# Default: 0 - disabled
|
# Default: 0 - disabled
|
||||||
@@ -295,7 +302,7 @@ AddonChannel = 1
|
|||||||
#
|
#
|
||||||
# DBLogLevel
|
# DBLogLevel
|
||||||
# Log level of DB logging.
|
# Log level of DB logging.
|
||||||
# 1 = Basic&Error; 2 = Detail; 3 = Full/Debug
|
# 0 = Minimum; 1 = Basic; 2 = Detail; 3 = Full/Debug
|
||||||
# Default: 3
|
# Default: 3
|
||||||
#
|
#
|
||||||
# LogDB.Char
|
# LogDB.Char
|
||||||
@@ -339,6 +346,7 @@ GmLogFile = "gm_commands.log"
|
|||||||
GmLogTimestamp = 0
|
GmLogTimestamp = 0
|
||||||
GmLogPerAccount = 0
|
GmLogPerAccount = 0
|
||||||
RaLogFile = "ra_commands.log"
|
RaLogFile = "ra_commands.log"
|
||||||
|
LogColors = ""
|
||||||
EnableLogDB = 0
|
EnableLogDB = 0
|
||||||
DBLogLevel = 1
|
DBLogLevel = 1
|
||||||
LogDB.Char = 0
|
LogDB.Char = 0
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ ConfVersion=2007062001
|
|||||||
#
|
#
|
||||||
# LogLevel
|
# LogLevel
|
||||||
# Server console level of logging
|
# Server console level of logging
|
||||||
# 0 = Minimum; 1 = Error; 2 = Detail; 3 = Full/Debug
|
# 0 = Minimum; 1 = Basic; 2 = Detail; 3 = Full/Debug
|
||||||
# Default: 0
|
# Default: 0
|
||||||
#
|
#
|
||||||
# LogFile
|
# LogFile
|
||||||
@@ -51,9 +51,16 @@ ConfVersion=2007062001
|
|||||||
#
|
#
|
||||||
# LogFileLevel
|
# LogFileLevel
|
||||||
# Server file level of logging
|
# Server file level of logging
|
||||||
# 0 = Minimum; 1 = Error; 2 = Detail; 3 = Full/Debug
|
# 0 = Minimum; 1 = Basic; 2 = Detail; 3 = Full/Debug
|
||||||
# Default: 0
|
# Default: 0
|
||||||
#
|
#
|
||||||
|
# LogColors
|
||||||
|
# Color for messages (format "normal error basic detail debug")
|
||||||
|
# Colors: 0 - BLACK, 1 - RED, 2 - GREEN, 3 - BROWN, 4 - BLUE, 5 - MAGENTA, 6 - CYAN, 7 - GREY,
|
||||||
|
# 8 - YELLOW, 9 - LRED, 10 - LGREEN, 11 - LBLUE, 12 - LMAGENTA, 13 - LCYAN, 14 - WHITE
|
||||||
|
# Default: "" - none colors
|
||||||
|
# Example: "13 7 11 9 5"
|
||||||
|
#
|
||||||
# EnableLogDB
|
# EnableLogDB
|
||||||
# Enable/disable logging to database (LogDatabaseInfo).
|
# Enable/disable logging to database (LogDatabaseInfo).
|
||||||
# Default: 0 - disabled
|
# Default: 0 - disabled
|
||||||
@@ -61,7 +68,7 @@ ConfVersion=2007062001
|
|||||||
#
|
#
|
||||||
# DBLogLevel
|
# DBLogLevel
|
||||||
# Log level of DB logging.
|
# Log level of DB logging.
|
||||||
# 1 = Basic&Error; 2 = Detail; 3 = Full/Debug
|
# 0 = Minimum; 1 = Basic; 2 = Detail; 3 = Full/Debug
|
||||||
# Default: 3
|
# Default: 3
|
||||||
#
|
#
|
||||||
# UseProcessors
|
# UseProcessors
|
||||||
@@ -112,5 +119,6 @@ RealmsStateUpdateDelay = 20
|
|||||||
WrongPass.MaxCount = 0
|
WrongPass.MaxCount = 0
|
||||||
WrongPass.BanTime = 600
|
WrongPass.BanTime = 600
|
||||||
WrongPass.BanType = 0
|
WrongPass.BanType = 0
|
||||||
|
LogColors = ""
|
||||||
EnableLogDB = 0
|
EnableLogDB = 0
|
||||||
DBLogLevel = 1
|
DBLogLevel = 1
|
||||||
|
|||||||
+158
-11
@@ -29,19 +29,9 @@
|
|||||||
|
|
||||||
INSTANTIATE_SINGLETON_1( Log );
|
INSTANTIATE_SINGLETON_1( Log );
|
||||||
|
|
||||||
enum LogType
|
|
||||||
{
|
|
||||||
LogNormal = 0,
|
|
||||||
LogDetails,
|
|
||||||
LogDebug,
|
|
||||||
LogError
|
|
||||||
};
|
|
||||||
|
|
||||||
const int LogType_count = int(LogError) +1;
|
|
||||||
|
|
||||||
Log::Log() :
|
Log::Log() :
|
||||||
raLogfile(NULL), logfile(NULL), gmLogfile(NULL), charLogfile(NULL),
|
raLogfile(NULL), logfile(NULL), gmLogfile(NULL), charLogfile(NULL),
|
||||||
dberLogfile(NULL), m_gmlog_per_account(false)
|
dberLogfile(NULL), m_gmlog_per_account(false), m_colored(false)
|
||||||
{
|
{
|
||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
@@ -118,6 +108,7 @@ void Log::Initialize()
|
|||||||
|
|
||||||
/// Open specific log files
|
/// Open specific log files
|
||||||
logfile = openLogFile("LogFile","LogTimestamp","w");
|
logfile = openLogFile("LogFile","LogTimestamp","w");
|
||||||
|
InitColors(sConfig.GetStringDefault("LogColors", ""));
|
||||||
|
|
||||||
m_gmlog_per_account = sConfig.GetBoolDefault("GmLogPerAccount",false);
|
m_gmlog_per_account = sConfig.GetBoolDefault("GmLogPerAccount",false);
|
||||||
if(!m_gmlog_per_account)
|
if(!m_gmlog_per_account)
|
||||||
@@ -203,6 +194,119 @@ FILE* Log::openGmlogPerAccount(uint32 account)
|
|||||||
return fopen(namebuf, "a");
|
return fopen(namebuf, "a");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Log::InitColors(const std::string& str)
|
||||||
|
{
|
||||||
|
if(str.empty())
|
||||||
|
{
|
||||||
|
m_colored = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int color[4];
|
||||||
|
|
||||||
|
std::istringstream ss(str);
|
||||||
|
|
||||||
|
for(int i = 0; i < LogLevels; ++i)
|
||||||
|
{
|
||||||
|
ss >> color[i];
|
||||||
|
|
||||||
|
if(!ss)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(color[i] < 0 || color[i] >= Colors)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < LogLevels; ++i)
|
||||||
|
m_colors[i] = ColorTypes(color[i]);
|
||||||
|
|
||||||
|
m_colored = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Log::SetColor(bool stdout_stream, ColorTypes color)
|
||||||
|
{
|
||||||
|
#if PLATFORM == PLATFORM_WINDOWS
|
||||||
|
static WORD WinColorFG[Colors] =
|
||||||
|
{
|
||||||
|
0, // BLACK
|
||||||
|
FOREGROUND_RED, // RED
|
||||||
|
FOREGROUND_GREEN, // GREEN
|
||||||
|
FOREGROUND_RED | FOREGROUND_GREEN, // BROWN
|
||||||
|
FOREGROUND_BLUE, // BLUE
|
||||||
|
FOREGROUND_RED | FOREGROUND_BLUE,// MAGENTA
|
||||||
|
FOREGROUND_GREEN | FOREGROUND_BLUE, // CYAN
|
||||||
|
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,// WHITE
|
||||||
|
// YELLOW
|
||||||
|
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
|
||||||
|
// RED_BOLD
|
||||||
|
FOREGROUND_RED | FOREGROUND_INTENSITY,
|
||||||
|
// GREEN_BOLD
|
||||||
|
FOREGROUND_GREEN | FOREGROUND_INTENSITY,
|
||||||
|
FOREGROUND_BLUE | FOREGROUND_INTENSITY, // BLUE_BOLD
|
||||||
|
// MAGENTA_BOLD
|
||||||
|
FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
|
||||||
|
// CYAN_BOLD
|
||||||
|
FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
|
||||||
|
// WHITE_BOLD
|
||||||
|
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
|
||||||
|
};
|
||||||
|
|
||||||
|
HANDLE hConsole = GetStdHandle(stdout_stream ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE );
|
||||||
|
SetConsoleTextAttribute(hConsole, WinColorFG[color]);
|
||||||
|
#else
|
||||||
|
enum ANSITextAttr
|
||||||
|
{
|
||||||
|
TA_NORMAL=0,
|
||||||
|
TA_BOLD=1,
|
||||||
|
TA_BLINK=5,
|
||||||
|
TA_REVERSE=7
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ANSIFgTextAttr
|
||||||
|
{
|
||||||
|
FG_BLACK=30, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
|
||||||
|
FG_MAGENTA, FG_CYAN, FG_WHITE, FG_YELLOW
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ANSIBgTextAttr
|
||||||
|
{
|
||||||
|
BG_BLACK=40, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
|
||||||
|
BG_MAGENTA, BG_CYAN, BG_WHITE
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8 UnixColorFG[Colors] =
|
||||||
|
{
|
||||||
|
FG_BLACK, // BLACK
|
||||||
|
FG_RED, // RED
|
||||||
|
FG_GREEN, // GREEN
|
||||||
|
FG_BROWN, // BROWN
|
||||||
|
FG_BLUE, // BLUE
|
||||||
|
FG_MAGENTA, // MAGENTA
|
||||||
|
FG_CYAN, // CYAN
|
||||||
|
FG_WHITE, // WHITE
|
||||||
|
FG_YELLOW, // YELLOW
|
||||||
|
FG_RED, // LRED
|
||||||
|
FG_GREEN, // LGREEN
|
||||||
|
FG_BLUE, // LBLUE
|
||||||
|
FG_MAGENTA, // LMAGENTA
|
||||||
|
FG_CYAN, // LCYAN
|
||||||
|
FG_WHITE // LWHITE
|
||||||
|
};
|
||||||
|
|
||||||
|
fprintf((stdout_stream? stdout : stderr), "\x1b[%d%sm", UnixColorFG[color], (color >= YELLOW && color < Colors ? ";1" : ""));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Log::ResetColor(bool stdout_stream)
|
||||||
|
{
|
||||||
|
#if PLATFORM == PLATFORM_WINDOWS
|
||||||
|
HANDLE hConsole = GetStdHandle(stdout_stream ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE );
|
||||||
|
SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED );
|
||||||
|
#else
|
||||||
|
fprintf(( stdout_stream ? stdout : stderr ), "\x1b[0m");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
std::string Log::GetTimestampStr()
|
std::string Log::GetTimestampStr()
|
||||||
{
|
{
|
||||||
time_t t = time(NULL);
|
time_t t = time(NULL);
|
||||||
@@ -259,8 +363,14 @@ void Log::outString( const char * str, ... )
|
|||||||
va_end(ap2);
|
va_end(ap2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(m_colored)
|
||||||
|
SetColor(true,m_colors[LOGL_NORMAL]);
|
||||||
|
|
||||||
UTF8PRINTF(stdout,str,);
|
UTF8PRINTF(stdout,str,);
|
||||||
|
|
||||||
|
if(m_colored)
|
||||||
|
ResetColor(true);
|
||||||
|
|
||||||
printf( "\n" );
|
printf( "\n" );
|
||||||
if(logfile)
|
if(logfile)
|
||||||
{
|
{
|
||||||
@@ -290,8 +400,14 @@ void Log::outError( const char * err, ... )
|
|||||||
va_end(ap2);
|
va_end(ap2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(m_colored)
|
||||||
|
SetColor(false,m_colors[LOGL_ERROR]);
|
||||||
|
|
||||||
UTF8PRINTF(stderr,err,);
|
UTF8PRINTF(stderr,err,);
|
||||||
|
|
||||||
|
if(m_colored)
|
||||||
|
ResetColor(false);
|
||||||
|
|
||||||
fprintf( stderr, "\n" );
|
fprintf( stderr, "\n" );
|
||||||
if(logfile)
|
if(logfile)
|
||||||
{
|
{
|
||||||
@@ -323,8 +439,14 @@ void Log::outErrorDb( const char * err, ... )
|
|||||||
va_end(ap2);
|
va_end(ap2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(m_colored)
|
||||||
|
SetColor(false,m_colors[LOGL_ERROR]);
|
||||||
|
|
||||||
UTF8PRINTF(stderr,err,);
|
UTF8PRINTF(stderr,err,);
|
||||||
|
|
||||||
|
if(m_colored)
|
||||||
|
ResetColor(false);
|
||||||
|
|
||||||
fprintf( stderr, "\n" );
|
fprintf( stderr, "\n" );
|
||||||
|
|
||||||
if(logfile)
|
if(logfile)
|
||||||
@@ -370,8 +492,14 @@ void Log::outBasic( const char * str, ... )
|
|||||||
|
|
||||||
if( m_logLevel > LOGL_NORMAL )
|
if( m_logLevel > LOGL_NORMAL )
|
||||||
{
|
{
|
||||||
|
if(m_colored)
|
||||||
|
SetColor(true,m_colors[LOGL_BASIC]);
|
||||||
|
|
||||||
UTF8PRINTF(stdout,str,);
|
UTF8PRINTF(stdout,str,);
|
||||||
|
|
||||||
|
if(m_colored)
|
||||||
|
ResetColor(true);
|
||||||
|
|
||||||
printf( "\n" );
|
printf( "\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,8 +532,14 @@ void Log::outDetail( const char * str, ... )
|
|||||||
|
|
||||||
if( m_logLevel > LOGL_BASIC )
|
if( m_logLevel > LOGL_BASIC )
|
||||||
{
|
{
|
||||||
|
if(m_colored)
|
||||||
|
SetColor(true,m_colors[LOGL_DETAIL]);
|
||||||
|
|
||||||
UTF8PRINTF(stdout,str,);
|
UTF8PRINTF(stdout,str,);
|
||||||
|
|
||||||
|
if(m_colored)
|
||||||
|
ResetColor(true);
|
||||||
|
|
||||||
printf( "\n" );
|
printf( "\n" );
|
||||||
}
|
}
|
||||||
if(logfile && m_logFileLevel > LOGL_BASIC)
|
if(logfile && m_logFileLevel > LOGL_BASIC)
|
||||||
@@ -425,6 +559,7 @@ void Log::outDebugInLine( const char * str, ... )
|
|||||||
{
|
{
|
||||||
if( !str )
|
if( !str )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( m_logLevel > LOGL_DETAIL )
|
if( m_logLevel > LOGL_DETAIL )
|
||||||
{
|
{
|
||||||
UTF8PRINTF(stdout,str,);
|
UTF8PRINTF(stdout,str,);
|
||||||
@@ -455,8 +590,14 @@ void Log::outDebug( const char * str, ... )
|
|||||||
|
|
||||||
if( m_logLevel > LOGL_DETAIL )
|
if( m_logLevel > LOGL_DETAIL )
|
||||||
{
|
{
|
||||||
|
if(m_colored)
|
||||||
|
SetColor(true,m_colors[LOGL_DEBUG]);
|
||||||
|
|
||||||
UTF8PRINTF(stdout,str,);
|
UTF8PRINTF(stdout,str,);
|
||||||
|
|
||||||
|
if(m_colored)
|
||||||
|
ResetColor(true);
|
||||||
|
|
||||||
printf( "\n" );
|
printf( "\n" );
|
||||||
}
|
}
|
||||||
if(logfile && m_logFileLevel > LOGL_DETAIL)
|
if(logfile && m_logFileLevel > LOGL_DETAIL)
|
||||||
@@ -490,8 +631,14 @@ void Log::outCommand( uint32 account, const char * str, ... )
|
|||||||
|
|
||||||
if( m_logLevel > LOGL_NORMAL )
|
if( m_logLevel > LOGL_NORMAL )
|
||||||
{
|
{
|
||||||
|
if(m_colored)
|
||||||
|
SetColor(true,m_colors[LOGL_BASIC]);
|
||||||
|
|
||||||
UTF8PRINTF(stdout,str,);
|
UTF8PRINTF(stdout,str,);
|
||||||
|
|
||||||
|
if(m_colored)
|
||||||
|
ResetColor(true);
|
||||||
|
|
||||||
printf( "\n" );
|
printf( "\n" );
|
||||||
}
|
}
|
||||||
if(logfile && m_logFileLevel > LOGL_NORMAL)
|
if(logfile && m_logFileLevel > LOGL_NORMAL)
|
||||||
|
|||||||
@@ -54,11 +54,35 @@ enum LogTypes
|
|||||||
enum LogLevel
|
enum LogLevel
|
||||||
{
|
{
|
||||||
LOGL_NORMAL = 0,
|
LOGL_NORMAL = 0,
|
||||||
|
LOGL_ERROR,
|
||||||
LOGL_BASIC,
|
LOGL_BASIC,
|
||||||
LOGL_DETAIL,
|
LOGL_DETAIL,
|
||||||
LOGL_DEBUG
|
LOGL_DEBUG
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const int LogLevels = int(LOGL_DEBUG)+1;
|
||||||
|
|
||||||
|
enum ColorTypes
|
||||||
|
{
|
||||||
|
BLACK,
|
||||||
|
RED,
|
||||||
|
GREEN,
|
||||||
|
BROWN,
|
||||||
|
BLUE,
|
||||||
|
MAGENTA,
|
||||||
|
CYAN,
|
||||||
|
GREY,
|
||||||
|
YELLOW,
|
||||||
|
LRED,
|
||||||
|
LGREEN,
|
||||||
|
LBLUE,
|
||||||
|
LMAGENTA,
|
||||||
|
LCYAN,
|
||||||
|
WHITE
|
||||||
|
};
|
||||||
|
|
||||||
|
const int Colors = int(WHITE)+1;
|
||||||
|
|
||||||
class Log : public Trinity::Singleton<Log, Trinity::ClassLevelLockable<Log, ZThread::FastMutex> >
|
class Log : public Trinity::Singleton<Log, Trinity::ClassLevelLockable<Log, ZThread::FastMutex> >
|
||||||
{
|
{
|
||||||
friend class Trinity::OperatorNew<Log>;
|
friend class Trinity::OperatorNew<Log>;
|
||||||
@@ -68,6 +92,10 @@ class Log : public Trinity::Singleton<Log, Trinity::ClassLevelLockable<Log, ZThr
|
|||||||
public:
|
public:
|
||||||
void Initialize();
|
void Initialize();
|
||||||
|
|
||||||
|
void InitColors(const std::string& init_str);
|
||||||
|
void SetColor(bool stdout_stream, ColorTypes color);
|
||||||
|
void ResetColor(bool stdout_stream);
|
||||||
|
|
||||||
void outDB( uint8 type, const char * str, ... ) ATTR_PRINTF(3,4);
|
void outDB( uint8 type, const char * str, ... ) ATTR_PRINTF(3,4);
|
||||||
void outString( const char * str, ... ) ATTR_PRINTF(2,3);
|
void outString( const char * str, ... ) ATTR_PRINTF(2,3);
|
||||||
void outError( const char * err, ... ) ATTR_PRINTF(2,3);
|
void outError( const char * err, ... ) ATTR_PRINTF(2,3);
|
||||||
@@ -117,6 +145,10 @@ class Log : public Trinity::Singleton<Log, Trinity::ClassLevelLockable<Log, ZThr
|
|||||||
bool m_enableLogDB;
|
bool m_enableLogDB;
|
||||||
uint32 realm;
|
uint32 realm;
|
||||||
|
|
||||||
|
// log coloring
|
||||||
|
bool m_colored;
|
||||||
|
ColorTypes m_colors[4];
|
||||||
|
|
||||||
// log levels:
|
// log levels:
|
||||||
// 0 minimum/string, 1 basic/error, 2 detail, 3 full/debug
|
// 0 minimum/string, 1 basic/error, 2 detail, 3 full/debug
|
||||||
uint8 m_dbLogLevel;
|
uint8 m_dbLogLevel;
|
||||||
|
|||||||
Reference in New Issue
Block a user