聊天相关fix
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
import { ChatAIService } from '../core/ChatAIService';
|
||||
|
||||
/**
|
||||
* ChatAI 批量测试运行器 - 纯脚本版本
|
||||
*
|
||||
* 用法:
|
||||
* ```typescript
|
||||
* const testRunner = new ChatAIBatchTestRunner();
|
||||
* testRunner.runBatchTest();
|
||||
* ```
|
||||
*/
|
||||
export class ChatAIBatchTestRunner {
|
||||
|
||||
private isRunning: boolean = false;
|
||||
|
||||
constructor() {
|
||||
console.log("[ChatAIBatchTestRunner] 测试运行器已初始化");
|
||||
}
|
||||
|
||||
/**
|
||||
* 延时工具函数
|
||||
* @param seconds 延时秒数
|
||||
*/
|
||||
private async delay(seconds: number): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(resolve, seconds * 1000);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行批量测试
|
||||
*/
|
||||
public async runBatchTest(): Promise<void> {
|
||||
if (this.isRunning) {
|
||||
console.log("[ChatAIBatchTestRunner] 测试已在运行中,请等待完成...");
|
||||
return;
|
||||
}
|
||||
|
||||
this.isRunning = true;
|
||||
console.log("[ChatAIBatchTestRunner] 开始批量测试角色ID 10001-10030");
|
||||
console.log("[ChatAIBatchTestRunner] 每次测试间隔10秒");
|
||||
|
||||
const startTime = Date.now();
|
||||
const successIds: number[] = [];
|
||||
const failureIds: number[] = [];
|
||||
const errorDetails: { [roleId: number]: string } = {};
|
||||
|
||||
// 测试角色ID 10001-10030
|
||||
for (let roleId = 10001; roleId <= 10030; roleId++) {
|
||||
console.log(`[ChatAIBatchTestRunner] 正在测试角色ID: ${roleId}`);
|
||||
|
||||
const testStartTime = Date.now();
|
||||
|
||||
try {
|
||||
const response = await ChatAIService.Instance.sendMessage(roleId, "hello");
|
||||
const testDuration = Date.now() - testStartTime;
|
||||
|
||||
if (response && response.trim() !== "") {
|
||||
successIds.push(roleId);
|
||||
console.log(`[ChatAIBatchTestRunner] ✅ 角色 ${roleId} 测试成功 (${testDuration}ms)`);
|
||||
console.log(`[ChatAIBatchTestRunner] 响应预览: ${response.substring(0, 50)}...`);
|
||||
} else {
|
||||
failureIds.push(roleId);
|
||||
errorDetails[roleId] = "返回空响应";
|
||||
console.log(`[ChatAIBatchTestRunner] ❌ 角色 ${roleId} 返回空响应 (${testDuration}ms)`);
|
||||
}
|
||||
} catch (error) {
|
||||
const testDuration = Date.now() - testStartTime;
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
|
||||
failureIds.push(roleId);
|
||||
errorDetails[roleId] = errorMessage;
|
||||
console.log(`[ChatAIBatchTestRunner] ❌ 角色 ${roleId} 测试失败 (${testDuration}ms): ${errorMessage}`);
|
||||
}
|
||||
|
||||
// 等待10秒(最后一个不需要等待)
|
||||
if (roleId < 10030) {
|
||||
console.log(`[ChatAIBatchTestRunner] 等待10秒后继续下一个测试...`);
|
||||
await this.delay(10);
|
||||
}
|
||||
}
|
||||
|
||||
const totalDuration = Date.now() - startTime;
|
||||
|
||||
// 输出最终报告
|
||||
this.printFinalReport(successIds, failureIds, errorDetails, totalDuration);
|
||||
|
||||
this.isRunning = false;
|
||||
console.log("[ChatAIBatchTestRunner] 批量测试完成!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出最终测试报告
|
||||
*/
|
||||
private printFinalReport(
|
||||
successIds: number[],
|
||||
failureIds: number[],
|
||||
errorDetails: { [roleId: number]: string },
|
||||
totalDuration: number
|
||||
): void {
|
||||
const totalTests = 30;
|
||||
const successCount = successIds.length;
|
||||
const failureCount = failureIds.length;
|
||||
const successRate = ((successCount / totalTests) * 100).toFixed(2);
|
||||
|
||||
console.log("\n" + "=".repeat(60));
|
||||
console.log(" ChatAI 批量测试报告");
|
||||
console.log("=".repeat(60));
|
||||
console.log(`测试时间: ${new Date().toLocaleString()}`);
|
||||
console.log(`总测试数: ${totalTests}`);
|
||||
console.log(`成功数量: ${successCount}`);
|
||||
console.log(`失败数量: ${failureCount}`);
|
||||
console.log(`成功率: ${successRate}%`);
|
||||
console.log(`总耗时: ${(totalDuration / 1000).toFixed(2)}秒`);
|
||||
console.log(`平均耗时: ${(totalDuration / totalTests / 1000).toFixed(2)}秒/测试`);
|
||||
|
||||
console.log("\n" + "-".repeat(30) + " 成功的角色ID " + "-".repeat(30));
|
||||
if (successIds.length > 0) {
|
||||
const successList = this.formatIdList(successIds);
|
||||
console.log(successList);
|
||||
} else {
|
||||
console.log("无成功案例");
|
||||
}
|
||||
|
||||
console.log("\n" + "-".repeat(30) + " 失败的角色ID " + "-".repeat(30));
|
||||
if (failureIds.length > 0) {
|
||||
const failureList = this.formatIdList(failureIds);
|
||||
console.log(failureList);
|
||||
|
||||
console.log("\n" + "-".repeat(25) + " 失败详情 " + "-".repeat(25));
|
||||
failureIds.forEach(roleId => {
|
||||
console.log(`角色 ${roleId}: ${errorDetails[roleId]}`);
|
||||
});
|
||||
} else {
|
||||
console.log("无失败案例");
|
||||
}
|
||||
|
||||
console.log("\n" + "=".repeat(60));
|
||||
|
||||
// 输出简洁版结果供复制使用
|
||||
console.log("\n简洁结果:");
|
||||
console.log(`成功(${successCount}): ${successIds.join(',')}`);
|
||||
console.log(`失败(${failureCount}): ${failureIds.join(',')}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化ID列表为易读格式
|
||||
*/
|
||||
private formatIdList(ids: number[]): string {
|
||||
if (ids.length === 0) return "无";
|
||||
|
||||
const sortedIds = ids.sort((a, b) => a - b);
|
||||
const groups: string[] = [];
|
||||
let start = sortedIds[0];
|
||||
let end = sortedIds[0];
|
||||
|
||||
for (let i = 1; i < sortedIds.length; i++) {
|
||||
if (sortedIds[i] === end + 1) {
|
||||
end = sortedIds[i];
|
||||
} else {
|
||||
if (start === end) {
|
||||
groups.push(`${start}`);
|
||||
} else if (end === start + 1) {
|
||||
groups.push(`${start},${end}`);
|
||||
} else {
|
||||
groups.push(`${start}-${end}`);
|
||||
}
|
||||
start = end = sortedIds[i];
|
||||
}
|
||||
}
|
||||
|
||||
// 添加最后一组
|
||||
if (start === end) {
|
||||
groups.push(`${start}`);
|
||||
} else if (end === start + 1) {
|
||||
groups.push(`${start},${end}`);
|
||||
} else {
|
||||
groups.push(`${start}-${end}`);
|
||||
}
|
||||
|
||||
return groups.join(', ');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前运行状态
|
||||
*/
|
||||
public isTestRunning(): boolean {
|
||||
return this.isRunning;
|
||||
}
|
||||
}
|
||||
|
||||
// 全局实例,可以直接调用
|
||||
export const chatAIBatchTester = new ChatAIBatchTestRunner();
|
||||
|
||||
// 便捷的全局函数
|
||||
export async function runChatAIBatchTest(): Promise<void> {
|
||||
await chatAIBatchTester.runBatchTest();
|
||||
}
|
||||
|
||||
// 使用示例:
|
||||
// import { runChatAIBatchTest } from 'path/to/ChatAIBatchTestRunner';
|
||||
// runChatAIBatchTest();
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "76e29352-9c31-48f1-ac08-8646aa63a425",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
import { _decorator, Component, Node, log, Button, Label } from 'cc';
|
||||
import { ChatAIService } from '../core/ChatAIService';
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
interface TestResult {
|
||||
roleId: number;
|
||||
success: boolean;
|
||||
response?: string;
|
||||
error?: string;
|
||||
duration: number;
|
||||
}
|
||||
|
||||
interface TestReport {
|
||||
totalTests: number;
|
||||
successCount: number;
|
||||
failureCount: number;
|
||||
successIds: number[];
|
||||
failureIds: number[];
|
||||
results: TestResult[];
|
||||
totalDuration: number;
|
||||
}
|
||||
|
||||
@ccclass('ChatAIServiceBatchTest')
|
||||
export class ChatAIServiceBatchTest extends Component {
|
||||
|
||||
@property(Button)
|
||||
startTestButton: Button = null;
|
||||
|
||||
@property(Label)
|
||||
statusLabel: Label = null;
|
||||
|
||||
@property(Label)
|
||||
resultLabel: Label = null;
|
||||
|
||||
private isTestRunning: boolean = false;
|
||||
private testReport: TestReport = null;
|
||||
|
||||
onLoad() {
|
||||
if (this.startTestButton) {
|
||||
this.startTestButton.node.on(Button.EventType.CLICK, this.startBatchTest, this);
|
||||
}
|
||||
|
||||
this.updateStatus("点击开始按钮进行批量测试");
|
||||
}
|
||||
|
||||
/**
|
||||
* 延时工具函数
|
||||
* @param seconds 延时秒数
|
||||
*/
|
||||
private async delay(seconds: number): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(resolve, seconds * 1000);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新状态显示
|
||||
*/
|
||||
private updateStatus(message: string): void {
|
||||
if (this.statusLabel) {
|
||||
this.statusLabel.string = message;
|
||||
}
|
||||
log(`[ChatAIBatchTest] ${message}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新结果显示
|
||||
*/
|
||||
private updateResult(report: TestReport): void {
|
||||
if (!this.resultLabel) return;
|
||||
|
||||
const resultText = `测试完成!
|
||||
总测试数: ${report.totalTests}
|
||||
成功数: ${report.successCount}
|
||||
失败数: ${report.failureCount}
|
||||
总耗时: ${(report.totalDuration / 1000).toFixed(2)}s
|
||||
|
||||
成功的ID: ${report.successIds.join(', ')}
|
||||
|
||||
失败的ID: ${report.failureIds.join(', ')}`;
|
||||
|
||||
this.resultLabel.string = resultText;
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试单个角色ID
|
||||
*/
|
||||
private async testSingleRole(roleId: number): Promise<TestResult> {
|
||||
const startTime = Date.now();
|
||||
|
||||
try {
|
||||
this.updateStatus(`正在测试角色ID: ${roleId}`);
|
||||
|
||||
const response = await ChatAIService.Instance.sendMessage(roleId, "hello");
|
||||
const duration = Date.now() - startTime;
|
||||
|
||||
if (response && response.trim() !== "") {
|
||||
log(`[ChatAIBatchTest] 角色 ${roleId} 测试成功: ${response.substring(0, 50)}...`);
|
||||
return {
|
||||
roleId,
|
||||
success: true,
|
||||
response: response.substring(0, 100), // 只记录前100字符
|
||||
duration
|
||||
};
|
||||
} else {
|
||||
log(`[ChatAIBatchTest] 角色 ${roleId} 返回空响应`);
|
||||
return {
|
||||
roleId,
|
||||
success: false,
|
||||
error: "返回空响应",
|
||||
duration
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
const duration = Date.now() - startTime;
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
log(`[ChatAIBatchTest] 角色 ${roleId} 测试失败: ${errorMessage}`);
|
||||
|
||||
return {
|
||||
roleId,
|
||||
success: false,
|
||||
error: errorMessage,
|
||||
duration
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始批量测试
|
||||
*/
|
||||
public async startBatchTest(): Promise<void> {
|
||||
if (this.isTestRunning) {
|
||||
this.updateStatus("测试正在进行中,请等待...");
|
||||
return;
|
||||
}
|
||||
|
||||
this.isTestRunning = true;
|
||||
|
||||
if (this.startTestButton) {
|
||||
this.startTestButton.interactable = false;
|
||||
}
|
||||
|
||||
if (this.resultLabel) {
|
||||
this.resultLabel.string = "";
|
||||
}
|
||||
|
||||
const startTime = Date.now();
|
||||
const results: TestResult[] = [];
|
||||
const successIds: number[] = [];
|
||||
const failureIds: number[] = [];
|
||||
|
||||
log("[ChatAIBatchTest] 开始批量测试角色ID 10001-10030");
|
||||
this.updateStatus("开始批量测试...");
|
||||
|
||||
// 测试角色ID 10001-10030
|
||||
for (let roleId = 10001; roleId <= 10030; roleId++) {
|
||||
try {
|
||||
// 测试单个角色
|
||||
const result = await this.testSingleRole(roleId);
|
||||
results.push(result);
|
||||
|
||||
if (result.success) {
|
||||
successIds.push(roleId);
|
||||
} else {
|
||||
failureIds.push(roleId);
|
||||
}
|
||||
|
||||
// 等待10秒(最后一个不需要等待)
|
||||
if (roleId < 10030) {
|
||||
this.updateStatus(`角色 ${roleId} 测试完成,等待10秒...`);
|
||||
await this.delay(10);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
log(`[ChatAIBatchTest] 测试角色 ${roleId} 时发生意外错误: ${error}`);
|
||||
results.push({
|
||||
roleId,
|
||||
success: false,
|
||||
error: `意外错误: ${error}`,
|
||||
duration: 0
|
||||
});
|
||||
failureIds.push(roleId);
|
||||
}
|
||||
}
|
||||
|
||||
const totalDuration = Date.now() - startTime;
|
||||
|
||||
// 生成测试报告
|
||||
this.testReport = {
|
||||
totalTests: 30,
|
||||
successCount: successIds.length,
|
||||
failureCount: failureIds.length,
|
||||
successIds,
|
||||
failureIds,
|
||||
results,
|
||||
totalDuration
|
||||
};
|
||||
|
||||
// 输出详细报告到控制台
|
||||
this.logDetailedReport(this.testReport);
|
||||
|
||||
// 更新UI显示
|
||||
this.updateResult(this.testReport);
|
||||
this.updateStatus("批量测试完成!");
|
||||
|
||||
if (this.startTestButton) {
|
||||
this.startTestButton.interactable = true;
|
||||
}
|
||||
|
||||
this.isTestRunning = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出详细测试报告到控制台
|
||||
*/
|
||||
private logDetailedReport(report: TestReport): void {
|
||||
log("========== ChatAI 批量测试报告 ==========");
|
||||
log(`测试时间: ${new Date().toLocaleString()}`);
|
||||
log(`总测试数: ${report.totalTests}`);
|
||||
log(`成功数: ${report.successCount}`);
|
||||
log(`失败数: ${report.failureCount}`);
|
||||
log(`成功率: ${((report.successCount / report.totalTests) * 100).toFixed(2)}%`);
|
||||
log(`总耗时: ${(report.totalDuration / 1000).toFixed(2)}秒`);
|
||||
log(`平均耗时: ${(report.totalDuration / report.totalTests / 1000).toFixed(2)}秒/测试`);
|
||||
|
||||
log("\n===== 成功的角色ID =====");
|
||||
if (report.successIds.length > 0) {
|
||||
log(report.successIds.join(', '));
|
||||
} else {
|
||||
log("无");
|
||||
}
|
||||
|
||||
log("\n===== 失败的角色ID =====");
|
||||
if (report.failureIds.length > 0) {
|
||||
log(report.failureIds.join(', '));
|
||||
|
||||
log("\n===== 失败详情 =====");
|
||||
report.results
|
||||
.filter(r => !r.success)
|
||||
.forEach(result => {
|
||||
log(`角色 ${result.roleId}: ${result.error}`);
|
||||
});
|
||||
} else {
|
||||
log("无");
|
||||
}
|
||||
|
||||
log("\n===== 详细测试结果 =====");
|
||||
report.results.forEach(result => {
|
||||
const status = result.success ? "成功" : "失败";
|
||||
const duration = (result.duration / 1000).toFixed(2);
|
||||
const extra = result.success
|
||||
? `响应: ${result.response?.substring(0, 30)}...`
|
||||
: `错误: ${result.error}`;
|
||||
log(`角色 ${result.roleId}: ${status} (${duration}s) - ${extra}`);
|
||||
});
|
||||
|
||||
log("========================================");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取测试报告(供外部调用)
|
||||
*/
|
||||
public getTestReport(): TestReport {
|
||||
return this.testReport;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置测试状态
|
||||
*/
|
||||
public resetTest(): void {
|
||||
this.isTestRunning = false;
|
||||
this.testReport = null;
|
||||
|
||||
if (this.statusLabel) {
|
||||
this.statusLabel.string = "点击开始按钮进行批量测试";
|
||||
}
|
||||
|
||||
if (this.resultLabel) {
|
||||
this.resultLabel.string = "";
|
||||
}
|
||||
|
||||
if (this.startTestButton) {
|
||||
this.startTestButton.interactable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "a95a7fa5-11a5-47f0-9cbe-6bd704cbbb74",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
# ChatAI 批量测试工具
|
||||
|
||||
本工具用于批量测试 ChatAIService 的 sendMessage 功能,测试角色ID 10001-10030 的可用性。
|
||||
|
||||
## 文件说明
|
||||
|
||||
### 1. ChatAIServiceBatchTest.ts
|
||||
- **类型**: Cocos Creator 组件
|
||||
- **用途**: 带UI界面的测试工具
|
||||
- **特点**: 需要挂载到节点上,有可视化界面
|
||||
|
||||
### 2. ChatAIBatchTestRunner.ts
|
||||
- **类型**: 纯TypeScript脚本
|
||||
- **用途**: 无UI的批量测试工具
|
||||
- **特点**: 可以直接在代码中调用
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 方法一:使用UI组件版本
|
||||
|
||||
1. 在Cocos Creator中创建一个测试场景
|
||||
2. 创建一个节点并挂载 `ChatAIServiceBatchTest` 组件
|
||||
3. 配置UI元素:
|
||||
- `startTestButton`: 开始测试按钮
|
||||
- `statusLabel`: 状态显示标签
|
||||
- `resultLabel`: 结果显示标签
|
||||
4. 运行场景,点击按钮开始测试
|
||||
|
||||
### 方法二:使用纯脚本版本(推荐)
|
||||
|
||||
在任何TypeScript文件中导入并调用:
|
||||
|
||||
```typescript
|
||||
import { runChatAIBatchTest } from 'db://assets/Scripts/chat18x/test/ChatAIBatchTestRunner';
|
||||
|
||||
// 直接运行测试
|
||||
runChatAIBatchTest();
|
||||
```
|
||||
|
||||
或者使用类实例:
|
||||
|
||||
```typescript
|
||||
import { ChatAIBatchTestRunner } from 'db://assets/Scripts/chat18x/test/ChatAIBatchTestRunner';
|
||||
|
||||
const testRunner = new ChatAIBatchTestRunner();
|
||||
await testRunner.runBatchTest();
|
||||
```
|
||||
|
||||
## 测试流程
|
||||
|
||||
1. 依次测试角色ID 10001 到 10030
|
||||
2. 对每个ID发送消息 "hello"
|
||||
3. 每次调用后等待10秒(最后一个测试不等待)
|
||||
4. 记录成功和失败的角色ID
|
||||
5. 输出详细的测试报告
|
||||
|
||||
## 测试报告内容
|
||||
|
||||
- 总测试数量
|
||||
- 成功/失败数量和比例
|
||||
- 成功的角色ID列表
|
||||
- 失败的角色ID列表及错误原因
|
||||
- 每个测试的耗时统计
|
||||
- 总耗时和平均耗时
|
||||
|
||||
## 示例输出
|
||||
|
||||
```
|
||||
==============================================================
|
||||
ChatAI 批量测试报告
|
||||
==============================================================
|
||||
测试时间: 2024/3/15 14:30:25
|
||||
总测试数: 30
|
||||
成功数量: 25
|
||||
失败数量: 5
|
||||
成功率: 83.33%
|
||||
总耗时: 315.68秒
|
||||
平均耗时: 10.52秒/测试
|
||||
|
||||
------------------------------ 成功的角色ID ------------------------------
|
||||
10001-10015, 10017-10025, 10028
|
||||
|
||||
------------------------------ 失败的角色ID ------------------------------
|
||||
10016, 10026, 10027, 10029, 10030
|
||||
|
||||
------------------------- 失败详情 -------------------------
|
||||
角色 10016: API调用超时
|
||||
角色 10026: 返回空响应
|
||||
角色 10027: 网络连接失败
|
||||
角色 10029: API密钥无效
|
||||
角色 10030: 角色配置不存在
|
||||
==============================================================
|
||||
|
||||
简洁结果:
|
||||
成功(25): 10001,10002,10003,10004,10005,10006,10007,10008,10009,10010,10011,10012,10013,10014,10015,10017,10018,10019,10020,10021,10022,10023,10024,10025,10028
|
||||
失败(5): 10016,10026,10027,10029,10030
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 确保 ChatAIService 已正确初始化
|
||||
2. 测试过程中不要关闭应用,总耗时约5-6分钟
|
||||
3. 测试结果会输出到控制台,注意查看
|
||||
4. 建议在开发环境下运行测试
|
||||
5. 如需中断测试,重启应用即可
|
||||
|
||||
## 技术细节
|
||||
|
||||
- 使用 Promise 和 async/await 处理异步操作
|
||||
- 通过 setTimeout 实现精确的10秒延时
|
||||
- 自动错误捕获和分类
|
||||
- 智能的ID列表格式化显示
|
||||
- 详细的执行时间统计
|
||||
|
||||
## 故障排除
|
||||
|
||||
如果测试无法启动:
|
||||
1. 检查 ChatAIService 是否正确导入
|
||||
2. 确认 AI API 配置是否有效
|
||||
3. 查看控制台错误信息
|
||||
4. 确保网络连接正常
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"importer": "text",
|
||||
"imported": true,
|
||||
"uuid": "0bad818f-088c-4639-905a-324516bbdafb",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
Reference in New Issue
Block a user