更新网页,11k
This commit is contained in:
parent
4e79f700dc
commit
b110c919bc
@ -1,5 +1,6 @@
|
|||||||
R"(<!DOCTYPE html>
|
R"(<!DOCTYPE html>
|
||||||
<html><head>
|
<html><head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
<title>W5500 Configuration</title>
|
<title>W5500 Configuration</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<style>
|
<style>
|
||||||
@ -13,9 +14,6 @@ R"(<!DOCTYPE html>
|
|||||||
h2 {
|
h2 {
|
||||||
color: #333;
|
color: #333;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-bottom: 10px;
|
|
||||||
border-bottom: 2px solid #ddd;
|
|
||||||
font-size: clamp(1.5rem, 4vw, 2rem);
|
|
||||||
}
|
}
|
||||||
form {
|
form {
|
||||||
background: white;
|
background: white;
|
||||||
@ -46,7 +44,7 @@ R"(<!DOCTYPE html>
|
|||||||
padding: 8px;
|
padding: 8px;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-family: monospace;
|
font-family: consolas;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
input[type='submit'] {
|
input[type='submit'] {
|
||||||
@ -140,6 +138,104 @@ R"(<!DOCTYPE html>
|
|||||||
background-color: #cccccc;
|
background-color: #cccccc;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.device-status,.network-config {
|
||||||
|
background: white;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
width: 100%;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 20px auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-item {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 200px;
|
||||||
|
padding: 15px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-item.full-width {
|
||||||
|
flex-basis: 100%;
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-item h3 {
|
||||||
|
margin: 0 0 10px 0;
|
||||||
|
color: #333;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-value {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-label {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: #dc3545;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success {
|
||||||
|
color: #28a745;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
color: #ffc107;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.status-item {
|
||||||
|
flex-basis: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-row.device-running {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-row.device-running .status-item {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 900px) {
|
||||||
|
.status-row.device-running .status-item {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
width: calc(33.33% - 10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 899px) {
|
||||||
|
.status-row.device-running .status-item {
|
||||||
|
flex: 1 1 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
@ -160,10 +256,134 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function updateDeviceStatus() {
|
||||||
|
fetch('/status')
|
||||||
|
.then(response => {
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
const deviceElement = document.getElementById('device-status');
|
||||||
|
deviceElement.textContent = data.deviceStatus ? '正常' : '异常';
|
||||||
|
deviceElement.className = data.deviceStatus ? 'success' : 'error';
|
||||||
|
|
||||||
|
const initStatus = ['等待', '成功', '失败'];
|
||||||
|
const initElement = document.getElementById('init-status');
|
||||||
|
initElement.textContent = initStatus[data.initStatus];
|
||||||
|
initElement.className = data.initStatus === 0 ? 'warning' : (data.initStatus === 1 ? 'success' : 'error');
|
||||||
|
|
||||||
|
const errorElement = document.getElementById('error-status');
|
||||||
|
errorElement.textContent = data.errorCode ? `Error: ${data.errorCode}` : '正常';
|
||||||
|
errorElement.className = data.errorCode ? 'error' : 'success';
|
||||||
|
|
||||||
|
const stopElement = document.getElementById('stop-status');
|
||||||
|
stopElement.textContent = data.stopStatus ? '停止' : '正常';
|
||||||
|
stopElement.className = data.stopStatus ? 'error' : 'success';
|
||||||
|
|
||||||
|
document.getElementById('valve1-angle').textContent = `${data.valves.angle1}°`;
|
||||||
|
document.getElementById('valve2-angle').textContent = `${data.valves.angle2}°`;
|
||||||
|
|
||||||
|
const pumpStatus = ['停止', '顺时针', '逆时针'];
|
||||||
|
document.getElementById('pump1-status').textContent =
|
||||||
|
`${pumpStatus[data.pumps.status1] || '#'} (${data.pumps.speed1}%)`;
|
||||||
|
document.getElementById('pump2-status').textContent =
|
||||||
|
`${pumpStatus[data.pumps.status2] || '#'} (${data.pumps.speed2}%)`;
|
||||||
|
|
||||||
|
const bubbleElement = document.getElementById('bubble-status');
|
||||||
|
bubbleElement.textContent = data.bubbleStatus ? '有' : '无';
|
||||||
|
bubbleElement.className = data.bubbleStatus ? 'error' : 'success';
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
|
||||||
|
console.error('Status update failed:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(updateDeviceStatus, 1000);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</head><body>
|
</head><body>
|
||||||
<h2>W5500 Network Configuration</h2>
|
<div class='device-status'>
|
||||||
|
<h2>状态信息</h2>
|
||||||
|
|
||||||
|
<div class='status-group'>
|
||||||
|
<!-- 设备信息行 -->
|
||||||
|
<div class='status-row'>
|
||||||
|
<div class='status-item full-width'>
|
||||||
|
<h3>Device Information</h3>
|
||||||
|
<div class='status-value'>
|
||||||
|
<span class='status-label'>Device Status:</span>
|
||||||
|
<span id='device-status'>#</span>
|
||||||
|
</div>
|
||||||
|
<div class='status-value'>
|
||||||
|
<span class='status-label'>Init Status:</span>
|
||||||
|
<span id='init-status'>#</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 设备运行状态行 -->
|
||||||
|
<div class='status-row device-running'>
|
||||||
|
<div class='status-item'>
|
||||||
|
<h3>Valve Status</h3>
|
||||||
|
<div class='status-value'>
|
||||||
|
<span class='status-label'>Valve 1 Angle:</span>
|
||||||
|
<span id='valve1-angle'>#</span>
|
||||||
|
</div>
|
||||||
|
<div class='status-value'>
|
||||||
|
<span class='status-label'>Valve 2 Angle:</span>
|
||||||
|
<span id='valve2-angle'>#</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='status-item'>
|
||||||
|
<h3>Pump Status</h3>
|
||||||
|
<div class='status-value'>
|
||||||
|
<span class='status-label'>Pump 1:</span>
|
||||||
|
<span id='pump1-status'>#</span>
|
||||||
|
</div>
|
||||||
|
<div class='status-value'>
|
||||||
|
<span class='status-label'>Pump 2:</span>
|
||||||
|
<span id='pump2-status'>#</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='status-item'>
|
||||||
|
<h3>Sensor Status</h3>
|
||||||
|
<div class='status-value'>
|
||||||
|
<span class='status-label'>Bubble Status:</span>
|
||||||
|
<span id='bubble-status'>#</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 急停状态 -->
|
||||||
|
<div class='status-row'>
|
||||||
|
<div class='status-item full-width'>
|
||||||
|
<h3>Emergency Stop</h3>
|
||||||
|
<div class='status-value'>
|
||||||
|
<span class='status-label'>Stop Status:</span>
|
||||||
|
<span id='stop-status'>#</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 错误状态行 -->
|
||||||
|
<div class='status-row'>
|
||||||
|
<div class='status-item full-width'>
|
||||||
|
<h3>Error Status</h3>
|
||||||
|
<div class='status-value'>
|
||||||
|
<span class='status-label'>Error Code:</span>
|
||||||
|
<span id='error-status'>#</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class='network-config'>
|
||||||
|
<h2>参数设置</h2>
|
||||||
<form method='post' action='/config'>
|
<form method='post' action='/config'>
|
||||||
<div class='form-group'>
|
<div class='form-group'>
|
||||||
<label>MAC:</label>
|
<label>MAC:</label>
|
||||||
@ -183,7 +403,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
</div>
|
</div>
|
||||||
<input type='submit' value='Save Configuration'>
|
<input type='submit' value='Save Configuration'>
|
||||||
</form>
|
</form>
|
||||||
<div class='status %s'>
|
|
||||||
Network Status: %s
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body></html>)"
|
</body></html>)"
|
@ -75,19 +75,15 @@ static void send_chunk_end(uint8_t sn)
|
|||||||
static void handle_config_page(uint8_t sn)
|
static void handle_config_page(uint8_t sn)
|
||||||
{
|
{
|
||||||
char buffer[CHUNK_SIZE];
|
char buffer[CHUNK_SIZE];
|
||||||
bool is_connected = (wizphy_getphylink() == PHY_LINK_ON);
|
|
||||||
char* link_status = is_connected ? "Connected" : "Disconnected";
|
|
||||||
char* status_class = is_connected ? "connected" : "disconnected";
|
|
||||||
|
|
||||||
// 先将完整的HTML内容格式化到一个临时缓冲区
|
// 先将完整的HTML内容格式化到一个临时缓冲区
|
||||||
char full_page[8192]; // 确保足够大
|
char full_page[1024*15]; // 确保足够大
|
||||||
int total_len = sprintf(full_page, index_html,
|
int total_len = sprintf(full_page, index_html,0,
|
||||||
gWIZNETINFO.mac[0], gWIZNETINFO.mac[1], gWIZNETINFO.mac[2],
|
gWIZNETINFO.mac[0], gWIZNETINFO.mac[1], gWIZNETINFO.mac[2],
|
||||||
gWIZNETINFO.mac[3], gWIZNETINFO.mac[4], gWIZNETINFO.mac[5],
|
gWIZNETINFO.mac[3], gWIZNETINFO.mac[4], gWIZNETINFO.mac[5],
|
||||||
gWIZNETINFO.ip[0], gWIZNETINFO.ip[1], gWIZNETINFO.ip[2], gWIZNETINFO.ip[3],
|
gWIZNETINFO.ip[0], gWIZNETINFO.ip[1], gWIZNETINFO.ip[2], gWIZNETINFO.ip[3],
|
||||||
gWIZNETINFO.sn[0], gWIZNETINFO.sn[1], gWIZNETINFO.sn[2], gWIZNETINFO.sn[3],
|
gWIZNETINFO.sn[0], gWIZNETINFO.sn[1], gWIZNETINFO.sn[2], gWIZNETINFO.sn[3],
|
||||||
gWIZNETINFO.gw[0], gWIZNETINFO.gw[1], gWIZNETINFO.gw[2], gWIZNETINFO.gw[3],
|
gWIZNETINFO.gw[0], gWIZNETINFO.gw[1], gWIZNETINFO.gw[2], gWIZNETINFO.gw[3]);
|
||||||
status_class, link_status);
|
|
||||||
|
|
||||||
// 发送响应头
|
// 发送响应头
|
||||||
send_chunked_response_header(sn);
|
send_chunked_response_header(sn);
|
||||||
@ -145,6 +141,118 @@ void http_server_init(void)
|
|||||||
listen(HTTP_SERVER_SOCKET);
|
listen(HTTP_SERVER_SOCKET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 三通阀结构体
|
||||||
|
typedef struct {
|
||||||
|
uint8_t angle1; // 阀门1角度 (120/210)
|
||||||
|
uint8_t angle2; // 阀门2角度 (120/210)
|
||||||
|
} ValveStatus;
|
||||||
|
|
||||||
|
// 泵结构体
|
||||||
|
typedef struct {
|
||||||
|
uint8_t status1; // 泵1运行状态 (停止/顺时针/逆时针)
|
||||||
|
uint8_t status2; // 泵2运行状态 (停止/顺时针/逆时针)
|
||||||
|
uint8_t speed1; // 泵1速度百分比 (0-100)
|
||||||
|
uint8_t speed2; // 泵2速度百分比 (0-100)
|
||||||
|
} PumpStatus;
|
||||||
|
|
||||||
|
// 设备状态结构体
|
||||||
|
// 1.下挂设备在位状态,在位为1,否则为0,当前为气泡感应器,1个字节
|
||||||
|
// 2.两个三通阀实时角度,每个角度占用1个字节,只能为210或120
|
||||||
|
// 3.泵状态,1表示泵顺时针转动中,2表示泵逆时针转动中,0表示停止,两个泵共2个字节
|
||||||
|
// 4.泵速度,2个字节,每个泵的速度占用一个字节,表示当前泵设定的速度百分比
|
||||||
|
// 5.气泡感应器读值,1表示监测到气泡,0表示没有气泡,共1个字节
|
||||||
|
// 6.急停按键状态,1个字节,1为按下,0为正常。
|
||||||
|
// 7.错误码1个字节,用于监控当前系统总体状态,如通信异常、控制异常等等,具体错误码待定
|
||||||
|
// 8.初始化状态,1个字节, 0表示初始化执行中,1表示初始化执行成功,2表示初始化执行失败。
|
||||||
|
typedef struct {
|
||||||
|
uint8_t deviceStatus; // 下挂设备状态
|
||||||
|
ValveStatus valves; // 两个三通阀状态
|
||||||
|
PumpStatus pumps; // 两个泵状态
|
||||||
|
uint8_t bubbleStatus; // 气泡状态
|
||||||
|
uint8_t stopStatus; // 急停状态
|
||||||
|
uint8_t errorCode; // 错误码
|
||||||
|
uint8_t initStatus; // 初始化状态
|
||||||
|
} DeviceStatus;
|
||||||
|
DeviceStatus deviceStatus={
|
||||||
|
.deviceStatus=1,
|
||||||
|
.valves={
|
||||||
|
.angle1=0,
|
||||||
|
.angle2=0
|
||||||
|
},
|
||||||
|
.pumps={
|
||||||
|
.status1=0,
|
||||||
|
.status2=0,
|
||||||
|
.speed1=60,
|
||||||
|
.speed2=70
|
||||||
|
},
|
||||||
|
.bubbleStatus=0,
|
||||||
|
.stopStatus=0,
|
||||||
|
.errorCode=0,
|
||||||
|
.initStatus=1
|
||||||
|
};
|
||||||
|
|
||||||
|
// 发送JSON响应头
|
||||||
|
static void send_json_response_header(uint8_t sn)
|
||||||
|
{
|
||||||
|
const char* header =
|
||||||
|
"HTTP/1.1 200 OK\r\n"
|
||||||
|
"Content-Type: application/json\r\n"
|
||||||
|
"Access-Control-Allow-Origin: *\r\n"
|
||||||
|
"Connection: close\r\n" // 明确指示关闭连接
|
||||||
|
"Cache-Control: no-cache, no-store\r\n" // 禁止缓存
|
||||||
|
"\r\n";
|
||||||
|
|
||||||
|
send_all(sn, (uint8_t*)header, strlen(header));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理状态请求
|
||||||
|
static void handle_status_request(uint8_t sn)
|
||||||
|
{
|
||||||
|
char json_buffer[512];
|
||||||
|
// DeviceStatus deviceStatus; // 确保能访问到deviceStatus变量
|
||||||
|
|
||||||
|
// 构建JSON响应
|
||||||
|
int len = sprintf(json_buffer,
|
||||||
|
"{"
|
||||||
|
"\"deviceStatus\":%d,"
|
||||||
|
"\"valves\":{"
|
||||||
|
"\"angle1\":%d,"
|
||||||
|
"\"angle2\":%d"
|
||||||
|
"},"
|
||||||
|
"\"pumps\":{"
|
||||||
|
"\"status1\":%d,"
|
||||||
|
"\"status2\":%d,"
|
||||||
|
"\"speed1\":%d,"
|
||||||
|
"\"speed2\":%d"
|
||||||
|
"},"
|
||||||
|
"\"bubbleStatus\":%d,"
|
||||||
|
"\"stopStatus\":%d,"
|
||||||
|
"\"errorCode\":%d,"
|
||||||
|
"\"initStatus\":%d"
|
||||||
|
"}",
|
||||||
|
deviceStatus.deviceStatus,
|
||||||
|
deviceStatus.valves.angle1,
|
||||||
|
deviceStatus.valves.angle2,
|
||||||
|
deviceStatus.pumps.status1,
|
||||||
|
deviceStatus.pumps.status2,
|
||||||
|
deviceStatus.pumps.speed1,
|
||||||
|
deviceStatus.pumps.speed2,
|
||||||
|
deviceStatus.bubbleStatus,
|
||||||
|
deviceStatus.stopStatus,
|
||||||
|
deviceStatus.errorCode,
|
||||||
|
deviceStatus.initStatus
|
||||||
|
);
|
||||||
|
|
||||||
|
// 发送响应
|
||||||
|
send_json_response_header(sn);
|
||||||
|
send_all(sn, (uint8_t*)json_buffer, len);
|
||||||
|
|
||||||
|
// 发送完成后主动关闭连接
|
||||||
|
disconnect(sn);
|
||||||
|
}
|
||||||
|
|
||||||
void http_server_task(void)
|
void http_server_task(void)
|
||||||
{
|
{
|
||||||
uint8_t buffer[2048];
|
uint8_t buffer[2048];
|
||||||
@ -153,13 +261,16 @@ void http_server_task(void)
|
|||||||
|
|
||||||
switch(status)
|
switch(status)
|
||||||
{
|
{
|
||||||
|
case SOCK_INIT:
|
||||||
|
listen(HTTP_SERVER_SOCKET);
|
||||||
|
break;
|
||||||
|
|
||||||
case SOCK_LISTEN:
|
case SOCK_LISTEN:
|
||||||
// 等待连接
|
// 等待连接
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SOCK_ESTABLISHED:
|
case SOCK_ESTABLISHED:
|
||||||
{
|
{
|
||||||
// 接收数据
|
|
||||||
if((size = getSn_RX_RSR(HTTP_SERVER_SOCKET)) > 0)
|
if((size = getSn_RX_RSR(HTTP_SERVER_SOCKET)) > 0)
|
||||||
{
|
{
|
||||||
size = recv(HTTP_SERVER_SOCKET, buffer, sizeof(buffer));
|
size = recv(HTTP_SERVER_SOCKET, buffer, sizeof(buffer));
|
||||||
@ -169,11 +280,14 @@ void http_server_task(void)
|
|||||||
parse_http_request(buffer, size, &req);
|
parse_http_request(buffer, size, &req);
|
||||||
|
|
||||||
if(req.method == HTTP_GET) {
|
if(req.method == HTTP_GET) {
|
||||||
|
if(strcmp(req.uri, "/status") == 0) {
|
||||||
|
handle_status_request(HTTP_SERVER_SOCKET);
|
||||||
|
} else {
|
||||||
handle_config_page(HTTP_SERVER_SOCKET);
|
handle_config_page(HTTP_SERVER_SOCKET);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if(req.method == HTTP_POST && strcmp(req.uri, "/config") == 0) {
|
else if(req.method == HTTP_POST && strcmp(req.uri, "/config") == 0) {
|
||||||
update_network_config((char*)req.body);
|
update_network_config((char*)req.body);
|
||||||
// 重定向回配置页面
|
|
||||||
send_chunked_response_header(HTTP_SERVER_SOCKET);
|
send_chunked_response_header(HTTP_SERVER_SOCKET);
|
||||||
send_chunk(HTTP_SERVER_SOCKET,
|
send_chunk(HTTP_SERVER_SOCKET,
|
||||||
"<html><head><meta http-equiv='refresh' content='0;url=/'></head></html>",
|
"<html><head><meta http-equiv='refresh' content='0;url=/'></head></html>",
|
||||||
@ -191,7 +305,6 @@ void http_server_task(void)
|
|||||||
|
|
||||||
case SOCK_CLOSED:
|
case SOCK_CLOSED:
|
||||||
socket(HTTP_SERVER_SOCKET, Sn_MR_TCP, HTTP_SERVER_PORT, 0);
|
socket(HTTP_SERVER_SOCKET, Sn_MR_TCP, HTTP_SERVER_PORT, 0);
|
||||||
listen(HTTP_SERVER_SOCKET);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user