mirror of
https://gitee.com/270580156/weiyu.git
synced 2025-12-30 10:52:26 +00:00
update
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"/admin/umi.css": "/admin/umi.c10bed78.css",
|
||||
"/admin/umi.js": "/admin/umi.b232a5b7.js",
|
||||
"/admin/umi.js": "/admin/umi.15ba68dc.js",
|
||||
"/admin/4940.76e573c2.async.js": "/admin/4940.76e573c2.async.js",
|
||||
"/admin/6571.d7d4f92f.async.js": "/admin/6571.d7d4f92f.async.js",
|
||||
"/admin/9952.56ca2544.async.js": "/admin/9952.56ca2544.async.js",
|
||||
@@ -132,7 +132,7 @@
|
||||
"/admin/p__Dashboard__Setting__Server__index.js": "/admin/p__Dashboard__Setting__Server__index.fe37a2f2.async.js",
|
||||
"/admin/p__Dashboard__Setting__Notification__index.js": "/admin/p__Dashboard__Setting__Notification__index.3285e515.async.js",
|
||||
"/admin/p__Dashboard__Setting__Webhook__index.js": "/admin/p__Dashboard__Setting__Webhook__index.3ba97cdf.async.js",
|
||||
"/admin/p__Dashboard__Setting__Token__index.js": "/admin/p__Dashboard__Setting__Token__index.788a009e.async.js",
|
||||
"/admin/p__Dashboard__Setting__Token__index.js": "/admin/p__Dashboard__Setting__Token__index.aec1044c.async.js",
|
||||
"/admin/p__Dashboard__Setting__License__index.js": "/admin/p__Dashboard__Setting__License__index.dc8e4c6b.async.js",
|
||||
"/admin/p__Dashboard__Super__Organization__index.js": "/admin/p__Dashboard__Super__Organization__index.bab3870c.async.js",
|
||||
"/admin/p__Dashboard__Super__User__index.js": "/admin/p__Dashboard__Super__User__index.b0b0a71c.async.js",
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<link rel="shortcut icon" href="/admin/favicon.ico">
|
||||
<title>微语</title>
|
||||
<link rel="stylesheet" href="/admin/umi.c10bed78.css">
|
||||
<script src="/admin/preload_helper.963beb06.js"></script>
|
||||
<script src="/admin/preload_helper.f61b1045.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script src="/admin/umi.b232a5b7.js"></script>
|
||||
<script src="/admin/umi.15ba68dc.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
import{getApiUrl as b}from"./index-CvNVT5L5.js";import{E as l}from"./index-x2o9k_ZH.js";async function f(t,r,i,a){try{const o=new Date().toISOString().replace(/[-:T.]/g,"").slice(0,14),p=r||`${o}_${t.name}`,s=i||t.type||"image/jpeg",e=new FormData;e.append("file",t),e.append("fileName",p),e.append("fileType",s),e.append("isAvatar",(a==null?void 0:a.isAvatar)||"false"),e.append("kbType",(a==null?void 0:a.kbType)||"feedback");const c=(a==null?void 0:a.visitorUid)||localStorage.getItem("bytedesk_uid")||localStorage.getItem("bytedesk_visitor_uid")||"",u=(a==null?void 0:a.visitorNickname)||localStorage.getItem("bytedesk_nickname")||"",g=(a==null?void 0:a.visitorAvatar)||localStorage.getItem("bytedesk_avatar")||"",v=(a==null?void 0:a.orgUid)||"";e.append("visitorUid",c),e.append("visitorNickname",u),e.append("visitorAvatar",g),e.append("orgUid",v),e.append("client",(a==null?void 0:a.client)||"web"),a!=null&&a.isDebug&&l.debug("handleUpload formData",e);const m=`${b()}/visitor/api/upload/file`,n=await fetch(m,{method:"POST",headers:{},body:e});if(!n.ok)throw new Error(`上传失败: ${n.status} ${n.statusText}`);const d=await n.json();return a!=null&&a.isDebug&&l.debug("upload data:",d),d}catch(o){throw l.error("文件上传失败:",o),o}}async function h(t,r){var i;const a=`screenshot_${new Date().toISOString().replace(/[-:T.]/g,"").slice(0,14)}.jpg`;return((i=(await f(t,a,"image/jpeg",{...r,kbType:"feedback"})).data)==null?void 0:i.fileUrl)||""}export{f as handleUpload,h as uploadScreenshot};
|
||||
import{getApiUrl as b}from"./index-Chq1FiPg.js";import{E as l}from"./index-7uwhsjz9.js";async function f(t,r,i,a){try{const o=new Date().toISOString().replace(/[-:T.]/g,"").slice(0,14),p=r||`${o}_${t.name}`,s=i||t.type||"image/jpeg",e=new FormData;e.append("file",t),e.append("fileName",p),e.append("fileType",s),e.append("isAvatar",(a==null?void 0:a.isAvatar)||"false"),e.append("kbType",(a==null?void 0:a.kbType)||"feedback");const c=(a==null?void 0:a.visitorUid)||localStorage.getItem("bytedesk_uid")||localStorage.getItem("bytedesk_visitor_uid")||"",u=(a==null?void 0:a.visitorNickname)||localStorage.getItem("bytedesk_nickname")||"",g=(a==null?void 0:a.visitorAvatar)||localStorage.getItem("bytedesk_avatar")||"",v=(a==null?void 0:a.orgUid)||"";e.append("visitorUid",c),e.append("visitorNickname",u),e.append("visitorAvatar",g),e.append("orgUid",v),e.append("client",(a==null?void 0:a.client)||"web"),a!=null&&a.isDebug&&l.debug("handleUpload formData",e);const m=`${b()}/visitor/api/upload/file`,n=await fetch(m,{method:"POST",headers:{},body:e});if(!n.ok)throw new Error(`上传失败: ${n.status} ${n.statusText}`);const d=await n.json();return a!=null&&a.isDebug&&l.debug("upload data:",d),d}catch(o){throw l.error("文件上传失败:",o),o}}async function h(t,r){var i;const a=`screenshot_${new Date().toISOString().replace(/[-:T.]/g,"").slice(0,14)}.jpg`;return((i=(await f(t,a,"image/jpeg",{...r,kbType:"feedback"})).data)==null?void 0:i.fileUrl)||""}export{f as handleUpload,h as uploadScreenshot};
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
import{T as a}from"./index-x2o9k_ZH.js";import r from"./index-CvNVT5L5.js";async function n(e){return r("/visitor/api/v1/message/unread/count",{method:"GET",params:{...e,client:a}})}async function o(e){return r("/visitor/api/v1/message/unread/clear",{method:"POST",data:{...e,client:a}})}export{o as clearUnreadMessages,n as getUnreadMessageCount};
|
||||
import{T as a}from"./index-7uwhsjz9.js";import r from"./index-Chq1FiPg.js";async function n(e){return r("/visitor/api/v1/message/unread/count",{method:"GET",params:{...e,client:a}})}async function o(e){return r("/visitor/api/v1/message/unread/clear",{method:"POST",data:{...e,client:a}})}export{o as clearUnreadMessages,n as getUnreadMessageCount};
|
||||
@@ -1 +1 @@
|
||||
import{T as t}from"./index-x2o9k_ZH.js";import o from"./index-CvNVT5L5.js";async function a(i){return o("/visitor/api/v1/init",{method:"POST",data:{...i,client:t}})}async function e(i){return o("/visitor/api/v1/browse",{method:"POST",data:{...i,client:t}})}export{e as browse,a as initVisitor};
|
||||
import{T as t}from"./index-7uwhsjz9.js";import o from"./index-Chq1FiPg.js";async function a(i){return o("/visitor/api/v1/init",{method:"POST",data:{...i,client:t}})}async function e(i){return o("/visitor/api/v1/browse",{method:"POST",data:{...i,client:t}})}export{e as browse,a as initVisitor};
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
import i from"./index-CvNVT5L5.js";import"./index-x2o9k_ZH.js";function e(t){return i({url:"/visitor/api/feedback/submit",method:"post",data:t})}export{e as submitFeedback};
|
||||
import i from"./index-Chq1FiPg.js";import"./index-7uwhsjz9.js";function e(t){return i({url:"/visitor/api/feedback/submit",method:"post",data:t})}export{e as submitFeedback};
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="UTF-8"/><link rel="icon" type="image/x-icon" href="/agent/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title></title><script type="module" crossorigin src="/agent/agent/assets/js/index-x2o9k_ZH.js"></script><link rel="stylesheet" crossorigin href="/agent/agent/assets/css/index-DMeNvbmc.css"></head><body><div id="root"></div><script src="https://cdn.weiyuai.cn/agent/assets/js/0.3.5/sdk.js"></script><script src="https://cdn.weiyuai.cn/agent/assets/js/2.0.2/index.js" async></script></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="UTF-8"/><link rel="icon" type="image/x-icon" href="/agent/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title></title><script type="module" crossorigin src="/agent/agent/assets/js/index-7uwhsjz9.js"></script><link rel="stylesheet" crossorigin href="/agent/agent/assets/css/index-DMeNvbmc.css"></head><body><div id="root"></div><script src="https://cdn.weiyuai.cn/agent/assets/js/0.3.5/sdk.js"></script><script src="https://cdn.weiyuai.cn/agent/assets/js/2.0.2/index.js" async></script></body></html>
|
||||
@@ -14,6 +14,7 @@ import java.util.Objects;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
@@ -30,6 +31,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@ConditionalOnProperty(prefix = "bytedesk.features.ai-bot", name = "enabled", havingValue = "true", matchIfMissing = false)
|
||||
@RequiredArgsConstructor
|
||||
public class AiBotHttapiController {
|
||||
|
||||
@@ -45,8 +47,8 @@ public class AiBotHttapiController {
|
||||
@Value("${bytedesk.call.ai.welcome:/usr/local/freeswitch/sounds/en/us/callie/ivr/8000/ivr-welcome.wav}")
|
||||
private String welcomeFile;
|
||||
|
||||
// 录音保存路径模板(放在 FS 本地),支持 ${uuid} 与 ${turn}
|
||||
@Value("${bytedesk.call.ai.recordPath:/usr/local/freeswitch/recordings/ai-bot-${uuid}-${turn}.wav}")
|
||||
// 录音保存路径模板(放在 FS 本地),支持 {uuid} 与 {turn}(避免 Spring 解析 ${...} 占位符导致启动失败)
|
||||
@Value("${bytedesk.call.ai.recordPath:/usr/local/freeswitch/recordings/ai-bot-{uuid}-{turn}.wav}")
|
||||
private String recordPathTpl;
|
||||
|
||||
// 最大录音秒数
|
||||
@@ -178,7 +180,12 @@ public class AiBotHttapiController {
|
||||
|
||||
private String resolveRecordPath(String tpl, String uuid, int turn) {
|
||||
String path = Objects.requireNonNullElse(tpl, "/usr/local/freeswitch/recordings/ai-bot-" + uuid + "-" + turn + ".wav");
|
||||
return path.replace("${uuid}", uuid).replace("${turn}", Integer.toString(turn));
|
||||
// 同时兼容 ${uuid}/${turn} 与 {uuid}/{turn} 两种模板写法
|
||||
return path
|
||||
.replace("${uuid}", uuid)
|
||||
.replace("${turn}", Integer.toString(turn))
|
||||
.replace("{uuid}", uuid)
|
||||
.replace("{turn}", Integer.toString(turn));
|
||||
}
|
||||
|
||||
private String safeAsr(String recordPath, String uuid, int turn) {
|
||||
|
||||
@@ -23,15 +23,21 @@
|
||||
|
||||
## 2. 关键配置
|
||||
|
||||
### 2.1 Spring Boot(端口、录音与调用)
|
||||
### 2.1 Spring Boot(启用开关、端口、录音与调用)
|
||||
|
||||
确保以下属性生效(可放在应用的 `application.properties` 或等效配置源中):
|
||||
默认不开启。要启用对话中枢 HTTAPI 控制器,请显式添加:
|
||||
|
||||
```
|
||||
bytedesk.features.ai-bot.enabled=true
|
||||
```
|
||||
|
||||
然后确保以下属性生效(可放在应用的 `application.properties` 或等效配置源中):
|
||||
|
||||
- `server.port=9003`(需与 dialplan 中的 HTTAPI URL 对齐)
|
||||
- modules/call(对话编排)
|
||||
- `bytedesk.call.ai.useSpeak=true`(可选:使用 `execute speak` 兜底)
|
||||
- `bytedesk.call.ai.welcome=/usr/local/freeswitch/sounds/en/us/callie/ivr/ivr-welcome.wav`(可改为自定义欢迎音)
|
||||
- `bytedesk.call.ai.recordPath=/usr/local/freeswitch/recordings/ai-bot-${uuid}-${turn}.wav`
|
||||
- `bytedesk.call.ai.recordPath=/usr/local/freeswitch/recordings/ai-bot-{uuid}-{turn}.wav`(支持 {uuid}/{turn},也向后兼容 ${uuid}/${turn})
|
||||
- `bytedesk.call.ai.recordMaxSec=10`
|
||||
- `bytedesk.call.ai.silenceSec=2`
|
||||
- `bytedesk.ai.service.baseUrl=http://127.0.0.1:9003`(指向本机 `modules/ai` 服务)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"/admin/umi.css": "/admin/umi.c10bed78.css",
|
||||
"/admin/umi.js": "/admin/umi.b232a5b7.js",
|
||||
"/admin/umi.js": "/admin/umi.15ba68dc.js",
|
||||
"/admin/4940.76e573c2.async.js": "/admin/4940.76e573c2.async.js",
|
||||
"/admin/6571.d7d4f92f.async.js": "/admin/6571.d7d4f92f.async.js",
|
||||
"/admin/9952.56ca2544.async.js": "/admin/9952.56ca2544.async.js",
|
||||
@@ -132,7 +132,7 @@
|
||||
"/admin/p__Dashboard__Setting__Server__index.js": "/admin/p__Dashboard__Setting__Server__index.fe37a2f2.async.js",
|
||||
"/admin/p__Dashboard__Setting__Notification__index.js": "/admin/p__Dashboard__Setting__Notification__index.3285e515.async.js",
|
||||
"/admin/p__Dashboard__Setting__Webhook__index.js": "/admin/p__Dashboard__Setting__Webhook__index.3ba97cdf.async.js",
|
||||
"/admin/p__Dashboard__Setting__Token__index.js": "/admin/p__Dashboard__Setting__Token__index.788a009e.async.js",
|
||||
"/admin/p__Dashboard__Setting__Token__index.js": "/admin/p__Dashboard__Setting__Token__index.aec1044c.async.js",
|
||||
"/admin/p__Dashboard__Setting__License__index.js": "/admin/p__Dashboard__Setting__License__index.dc8e4c6b.async.js",
|
||||
"/admin/p__Dashboard__Super__Organization__index.js": "/admin/p__Dashboard__Super__Organization__index.bab3870c.async.js",
|
||||
"/admin/p__Dashboard__Super__User__index.js": "/admin/p__Dashboard__Super__User__index.b0b0a71c.async.js",
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<link rel="shortcut icon" href="/admin/favicon.ico">
|
||||
<title>微语</title>
|
||||
<link rel="stylesheet" href="/admin/umi.c10bed78.css">
|
||||
<script src="/admin/preload_helper.963beb06.js"></script>
|
||||
<script src="/admin/preload_helper.f61b1045.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script src="/admin/umi.b232a5b7.js"></script>
|
||||
<script src="/admin/umi.15ba68dc.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
import{getApiUrl as b}from"./index-CvNVT5L5.js";import{E as l}from"./index-x2o9k_ZH.js";async function f(t,r,i,a){try{const o=new Date().toISOString().replace(/[-:T.]/g,"").slice(0,14),p=r||`${o}_${t.name}`,s=i||t.type||"image/jpeg",e=new FormData;e.append("file",t),e.append("fileName",p),e.append("fileType",s),e.append("isAvatar",(a==null?void 0:a.isAvatar)||"false"),e.append("kbType",(a==null?void 0:a.kbType)||"feedback");const c=(a==null?void 0:a.visitorUid)||localStorage.getItem("bytedesk_uid")||localStorage.getItem("bytedesk_visitor_uid")||"",u=(a==null?void 0:a.visitorNickname)||localStorage.getItem("bytedesk_nickname")||"",g=(a==null?void 0:a.visitorAvatar)||localStorage.getItem("bytedesk_avatar")||"",v=(a==null?void 0:a.orgUid)||"";e.append("visitorUid",c),e.append("visitorNickname",u),e.append("visitorAvatar",g),e.append("orgUid",v),e.append("client",(a==null?void 0:a.client)||"web"),a!=null&&a.isDebug&&l.debug("handleUpload formData",e);const m=`${b()}/visitor/api/upload/file`,n=await fetch(m,{method:"POST",headers:{},body:e});if(!n.ok)throw new Error(`上传失败: ${n.status} ${n.statusText}`);const d=await n.json();return a!=null&&a.isDebug&&l.debug("upload data:",d),d}catch(o){throw l.error("文件上传失败:",o),o}}async function h(t,r){var i;const a=`screenshot_${new Date().toISOString().replace(/[-:T.]/g,"").slice(0,14)}.jpg`;return((i=(await f(t,a,"image/jpeg",{...r,kbType:"feedback"})).data)==null?void 0:i.fileUrl)||""}export{f as handleUpload,h as uploadScreenshot};
|
||||
import{getApiUrl as b}from"./index-Chq1FiPg.js";import{E as l}from"./index-7uwhsjz9.js";async function f(t,r,i,a){try{const o=new Date().toISOString().replace(/[-:T.]/g,"").slice(0,14),p=r||`${o}_${t.name}`,s=i||t.type||"image/jpeg",e=new FormData;e.append("file",t),e.append("fileName",p),e.append("fileType",s),e.append("isAvatar",(a==null?void 0:a.isAvatar)||"false"),e.append("kbType",(a==null?void 0:a.kbType)||"feedback");const c=(a==null?void 0:a.visitorUid)||localStorage.getItem("bytedesk_uid")||localStorage.getItem("bytedesk_visitor_uid")||"",u=(a==null?void 0:a.visitorNickname)||localStorage.getItem("bytedesk_nickname")||"",g=(a==null?void 0:a.visitorAvatar)||localStorage.getItem("bytedesk_avatar")||"",v=(a==null?void 0:a.orgUid)||"";e.append("visitorUid",c),e.append("visitorNickname",u),e.append("visitorAvatar",g),e.append("orgUid",v),e.append("client",(a==null?void 0:a.client)||"web"),a!=null&&a.isDebug&&l.debug("handleUpload formData",e);const m=`${b()}/visitor/api/upload/file`,n=await fetch(m,{method:"POST",headers:{},body:e});if(!n.ok)throw new Error(`上传失败: ${n.status} ${n.statusText}`);const d=await n.json();return a!=null&&a.isDebug&&l.debug("upload data:",d),d}catch(o){throw l.error("文件上传失败:",o),o}}async function h(t,r){var i;const a=`screenshot_${new Date().toISOString().replace(/[-:T.]/g,"").slice(0,14)}.jpg`;return((i=(await f(t,a,"image/jpeg",{...r,kbType:"feedback"})).data)==null?void 0:i.fileUrl)||""}export{f as handleUpload,h as uploadScreenshot};
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
import{T as a}from"./index-x2o9k_ZH.js";import r from"./index-CvNVT5L5.js";async function n(e){return r("/visitor/api/v1/message/unread/count",{method:"GET",params:{...e,client:a}})}async function o(e){return r("/visitor/api/v1/message/unread/clear",{method:"POST",data:{...e,client:a}})}export{o as clearUnreadMessages,n as getUnreadMessageCount};
|
||||
import{T as a}from"./index-7uwhsjz9.js";import r from"./index-Chq1FiPg.js";async function n(e){return r("/visitor/api/v1/message/unread/count",{method:"GET",params:{...e,client:a}})}async function o(e){return r("/visitor/api/v1/message/unread/clear",{method:"POST",data:{...e,client:a}})}export{o as clearUnreadMessages,n as getUnreadMessageCount};
|
||||
@@ -1 +1 @@
|
||||
import{T as t}from"./index-x2o9k_ZH.js";import o from"./index-CvNVT5L5.js";async function a(i){return o("/visitor/api/v1/init",{method:"POST",data:{...i,client:t}})}async function e(i){return o("/visitor/api/v1/browse",{method:"POST",data:{...i,client:t}})}export{e as browse,a as initVisitor};
|
||||
import{T as t}from"./index-7uwhsjz9.js";import o from"./index-Chq1FiPg.js";async function a(i){return o("/visitor/api/v1/init",{method:"POST",data:{...i,client:t}})}async function e(i){return o("/visitor/api/v1/browse",{method:"POST",data:{...i,client:t}})}export{e as browse,a as initVisitor};
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
import i from"./index-CvNVT5L5.js";import"./index-x2o9k_ZH.js";function e(t){return i({url:"/visitor/api/feedback/submit",method:"post",data:t})}export{e as submitFeedback};
|
||||
import i from"./index-Chq1FiPg.js";import"./index-7uwhsjz9.js";function e(t){return i({url:"/visitor/api/feedback/submit",method:"post",data:t})}export{e as submitFeedback};
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="UTF-8"/><link rel="icon" type="image/x-icon" href="/agent/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title></title><script type="module" crossorigin src="/agent/agent/assets/js/index-x2o9k_ZH.js"></script><link rel="stylesheet" crossorigin href="/agent/agent/assets/css/index-DMeNvbmc.css"></head><body><div id="root"></div><script src="https://cdn.weiyuai.cn/agent/assets/js/0.3.5/sdk.js"></script><script src="https://cdn.weiyuai.cn/agent/assets/js/2.0.2/index.js" async></script></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="UTF-8"/><link rel="icon" type="image/x-icon" href="/agent/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title></title><script type="module" crossorigin src="/agent/agent/assets/js/index-7uwhsjz9.js"></script><link rel="stylesheet" crossorigin href="/agent/agent/assets/css/index-DMeNvbmc.css"></head><body><div id="root"></div><script src="https://cdn.weiyuai.cn/agent/assets/js/0.3.5/sdk.js"></script><script src="https://cdn.weiyuai.cn/agent/assets/js/2.0.2/index.js" async></script></body></html>
|
||||
Reference in New Issue
Block a user