Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
59b9a0e207
@ -1,28 +1,28 @@
|
|||||||
{
|
{
|
||||||
"name" : "xinelu-applet-ui",
|
"name": "xinelu-applet-ui",
|
||||||
"appid" : "__UNI__EA0DD4F",
|
"appid": "__UNI__EA0DD4F",
|
||||||
"description" : "",
|
"description": "",
|
||||||
"versionName" : "1.0.0",
|
"versionName": "1.0.0",
|
||||||
"versionCode" : "100",
|
"versionCode": "100",
|
||||||
"transformPx" : false,
|
"transformPx": false,
|
||||||
/* 5+App特有相关 */
|
/* 5+App特有相关 */
|
||||||
"app-plus" : {
|
"app-plus": {
|
||||||
"usingComponents" : true,
|
"usingComponents": true,
|
||||||
"nvueStyleCompiler" : "uni-app",
|
"nvueStyleCompiler": "uni-app",
|
||||||
"compilerVersion" : 3,
|
"compilerVersion": 3,
|
||||||
"splashscreen" : {
|
"splashscreen": {
|
||||||
"alwaysShowBeforeRender" : true,
|
"alwaysShowBeforeRender": true,
|
||||||
"waiting" : true,
|
"waiting": true,
|
||||||
"autoclose" : true,
|
"autoclose": true,
|
||||||
"delay" : 0
|
"delay": 0
|
||||||
},
|
},
|
||||||
/* 模块配置 */
|
/* 模块配置 */
|
||||||
"modules" : {},
|
"modules": {},
|
||||||
/* 应用发布信息 */
|
/* 应用发布信息 */
|
||||||
"distribute" : {
|
"distribute": {
|
||||||
/* android打包配置 */
|
/* android打包配置 */
|
||||||
"android" : {
|
"android": {
|
||||||
"permissions" : [
|
"permissions": [
|
||||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||||
@ -41,55 +41,56 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
/* ios打包配置 */
|
/* ios打包配置 */
|
||||||
"ios" : {},
|
"ios": {},
|
||||||
/* SDK配置 */
|
/* SDK配置 */
|
||||||
"sdkConfigs" : {}
|
"sdkConfigs": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/* 快应用特有相关 */
|
/* 快应用特有相关 */
|
||||||
"quickapp" : {},
|
"quickapp": {},
|
||||||
/* 小程序特有相关 */
|
/* 小程序特有相关 */
|
||||||
"mp-weixin" : {
|
"mp-weixin": {
|
||||||
"appid" : "wxccb16a452ab5e4b4",
|
"appid": "wxccb16a452ab5e4b4",
|
||||||
"setting" : {
|
"__usePrivacyCheck__": true,
|
||||||
"urlCheck" : false,
|
"setting": {
|
||||||
"postcss" : true,
|
"urlCheck": false,
|
||||||
"minified" : true,
|
"postcss": true,
|
||||||
"es6" : true
|
"minified": true,
|
||||||
|
"es6": true
|
||||||
},
|
},
|
||||||
"usingComponents" : true,
|
"usingComponents": true,
|
||||||
// app.json
|
// app.json
|
||||||
"permission" : {
|
"permission": {
|
||||||
"scope.userLocation" : {
|
"scope.userLocation": {
|
||||||
"desc" : "你的位置信息将用于护理机构列表的位置查询"
|
"desc": "你的位置信息将用于护理机构列表的位置查询"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"requiredPrivateInfos" : [ "chooseLocation", "getLocation" ],
|
"requiredPrivateInfos": ["chooseLocation", "getLocation"],
|
||||||
// "plugins": {
|
// "plugins": {
|
||||||
// "chooseLocation": {
|
// "chooseLocation": {
|
||||||
// "version": "1.0.9",
|
// "version": "1.0.9",
|
||||||
// "provider": "wx76a9a06e5b4e693e"
|
// "provider": "wx76a9a06e5b4e693e"
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
"uniStatistics" : {
|
"uniStatistics": {
|
||||||
"enable" : true
|
"enable": true
|
||||||
},
|
},
|
||||||
"lazyCodeLoading" : "requiredComponents",
|
"lazyCodeLoading": "requiredComponents",
|
||||||
"unipush" : {
|
"unipush": {
|
||||||
"enable" : false
|
"enable": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mp-alipay" : {
|
"mp-alipay": {
|
||||||
"usingComponents" : true
|
"usingComponents": true
|
||||||
},
|
},
|
||||||
"mp-baidu" : {
|
"mp-baidu": {
|
||||||
"usingComponents" : true
|
"usingComponents": true
|
||||||
},
|
},
|
||||||
"mp-toutiao" : {
|
"mp-toutiao": {
|
||||||
"usingComponents" : true
|
"usingComponents": true
|
||||||
},
|
},
|
||||||
"uniStatistics" : {
|
"uniStatistics": {
|
||||||
"enable" : false
|
"enable": false
|
||||||
},
|
},
|
||||||
"vueVersion" : "2"
|
"vueVersion": "2"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,6 +40,13 @@
|
|||||||
}
|
}
|
||||||
this.phonecode = undefined
|
this.phonecode = undefined
|
||||||
this.logincode = undefined
|
this.logincode = undefined
|
||||||
|
let that = this
|
||||||
|
wx.login({
|
||||||
|
provider: 'weixin',
|
||||||
|
success: function(loginRes) {
|
||||||
|
that.logincode = loginRes.code
|
||||||
|
}
|
||||||
|
});
|
||||||
// this.scenenurseStationId = uni.getStorageSync('scenenurseStationId');
|
// this.scenenurseStationId = uni.getStorageSync('scenenurseStationId');
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -90,14 +97,8 @@
|
|||||||
let that = this;
|
let that = this;
|
||||||
if (val.detail.code) {
|
if (val.detail.code) {
|
||||||
that.phonecode = val.detail.code
|
that.phonecode = val.detail.code
|
||||||
wx.login({
|
|
||||||
provider: 'weixin',
|
|
||||||
success: function(loginRes) {
|
|
||||||
that.logincode = loginRes.code
|
|
||||||
that.login();
|
that.login();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
login() {
|
login() {
|
||||||
let that = this;
|
let that = this;
|
||||||
|
|||||||
@ -532,11 +532,8 @@
|
|||||||
},
|
},
|
||||||
// 专家咨询订单
|
// 专家咨询订单
|
||||||
expertOrder() {
|
expertOrder() {
|
||||||
// uni.navigateTo({
|
|
||||||
// url: "/pagesB/ExpertlookOrder/ExpertlookOrder"
|
|
||||||
// })
|
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: "/pagesmeeting/calling"
|
url: "/pagesB/ExpertlookOrder/ExpertlookOrder"
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,16 +24,15 @@
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
goroom() {
|
goroom() {
|
||||||
|
this.checkDeviceAuthorize().then((result) => {
|
||||||
|
console.log('授权成功', result)
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pagesmeeting/calling?userID=${this.item.patientId}&userName=${this.item.patientName}&userSig=${this.userSig}&roomID=${this.roomId}`
|
url: `/pagesmeeting/room/room?sdkAppID=1600006944&localVideo=true&localAudio=true&userID=${this.item.patientId}&userName=${this.item.receiver}&userSig=${this.userSig}&roomID=${this.roomId}`
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log('没有授权', error)
|
||||||
})
|
})
|
||||||
// this.checkDeviceAuthorize().then((result) => {
|
|
||||||
// console.log('授权成功', result)
|
|
||||||
|
|
||||||
// })
|
|
||||||
// .catch((error) => {
|
|
||||||
// console.log('没有授权', error)
|
|
||||||
// })
|
|
||||||
},
|
},
|
||||||
checkDeviceAuthorize() {
|
checkDeviceAuthorize() {
|
||||||
this.hasOpenDeviceAuthorizeModal = false
|
this.hasOpenDeviceAuthorizeModal = false
|
||||||
|
|||||||
@ -28,9 +28,9 @@
|
|||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import {
|
// import {
|
||||||
genTestUserSig
|
// genTestUserSig
|
||||||
} from './debug/GenerateTestUserSig'
|
// } from './debug/GenerateTestUserSig'
|
||||||
import {
|
import {
|
||||||
mapState
|
mapState
|
||||||
} from 'vuex';
|
} from 'vuex';
|
||||||
@ -83,9 +83,9 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
const userID = '123'; //userID
|
const userID = '123'; //userID
|
||||||
const Signature = genTestUserSig(userID)
|
// const Signature = genTestUserSig(userID)
|
||||||
const url =
|
// const url =
|
||||||
`./room/room?roomID=${this.roomID}&localVideo=${this.localVideo}&localAudio=${this.localAudio}&userID=${userID}&sdkAppID=${Signature.sdkAppID}&userSig=${Signature.userSig}`
|
// `./room/room?roomID=${this.roomID}&localVideo=${this.localVideo}&localAudio=${this.localAudio}&userID=${userID}&sdkAppID=${Signature.sdkAppID}&userSig=${Signature.userSig}`
|
||||||
this.tapTime = nowTime
|
this.tapTime = nowTime
|
||||||
this.checkDeviceAuthorize().then((result) => {
|
this.checkDeviceAuthorize().then((result) => {
|
||||||
console.log('授权成功', result)
|
console.log('授权成功', result)
|
||||||
|
|||||||
@ -1,59 +0,0 @@
|
|||||||
import LibGenerateTestUserSig from './lib-generate-test-usersig-es.min.js';
|
|
||||||
/**
|
|
||||||
* 腾讯云 SDKAppId,需要替换为您自己账号下的 SDKAppId。
|
|
||||||
*
|
|
||||||
* 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ) 创建应用,即可看到 SDKAppId,
|
|
||||||
* 它是腾讯云用于区分客户的唯一标识。
|
|
||||||
*/
|
|
||||||
|
|
||||||
const SDKAPPID = 1600006944; //请设置为实际的 SDKAppID
|
|
||||||
/**
|
|
||||||
* 签名过期时间,建议不要设置的过短
|
|
||||||
* <p>
|
|
||||||
* 时间单位:秒
|
|
||||||
* 默认时间:7 x 24 x 60 x 60 = 604800 = 7 天
|
|
||||||
*/
|
|
||||||
|
|
||||||
const EXPIRETIME = 604800;
|
|
||||||
/**
|
|
||||||
* 计算签名用的加密密钥,获取步骤如下:
|
|
||||||
*
|
|
||||||
* step1. 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ),如果还没有应用就创建一个,
|
|
||||||
* step2. 单击“应用配置”进入基础配置页面,并进一步找到“帐号体系集成”部分。
|
|
||||||
* step3. 点击“查看密钥”按钮,就可以看到计算 UserSig 使用的加密的密钥了,请将其拷贝并复制到如下的变量中
|
|
||||||
*
|
|
||||||
* 注意:该方案仅适用于调试Demo,正式上线前请将 UserSig 计算代码和密钥迁移到您的后台服务器上,以避免加密密钥泄露导致的流量盗用。
|
|
||||||
* 文档:https://cloud.tencent.com/document/product/647/17275#Server
|
|
||||||
*/
|
|
||||||
|
|
||||||
const SECRETKEY = '6ddbc3e7e4aa128b52898df27a35f8f3d5acdca6f34ffa17b87ebc33e83314f1'; //将 密钥 粘贴到此处
|
|
||||||
/*
|
|
||||||
* Module: GenerateTestUserSig
|
|
||||||
*
|
|
||||||
* Function: 用于生成测试用的 UserSig,UserSig 是腾讯云为其云服务设计的一种安全保护签名。
|
|
||||||
* 其计算方法是对 SDKAppID、UserID 和 EXPIRETIME 进行加密,加密算法为 HMAC-SHA256。
|
|
||||||
*
|
|
||||||
* Attention: 请不要将如下代码发布到您的线上正式版本的 App 中,原因如下:
|
|
||||||
*
|
|
||||||
* 本文件中的代码虽然能够正确计算出 UserSig,但仅适合快速调通 SDK 的基本功能,不适合线上产品,
|
|
||||||
* 这是因为客户端代码中的 SECRETKEY 很容易被反编译逆向破解,尤其是 Web 端的代码被破解的难度几乎为零。
|
|
||||||
* 一旦您的密钥泄露,攻击者就可以计算出正确的 UserSig 来盗用您的腾讯云流量。
|
|
||||||
*
|
|
||||||
* 正确的做法是将 UserSig 的计算代码和加密密钥放在您的业务服务器上,然后由 App 按需向您的服务器获取实时算出的 UserSig。
|
|
||||||
* 由于破解服务器的成本要高于破解客户端 App,所以服务器计算的方案能够更好地保护您的加密密钥。
|
|
||||||
*
|
|
||||||
* Reference:https://cloud.tencent.com/document/product/647/17275#Server
|
|
||||||
*/
|
|
||||||
|
|
||||||
function genTestUserSig(userID) {
|
|
||||||
const generator = new LibGenerateTestUserSig(SDKAPPID, SECRETKEY, EXPIRETIME);
|
|
||||||
const userSig = generator.genTestUserSig(userID);
|
|
||||||
return {
|
|
||||||
sdkAppID: SDKAPPID,
|
|
||||||
userSig
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
genTestUserSig
|
|
||||||
};
|
|
||||||
6217
pagesmeeting/debug/lib-generate-test-usersig-es.min.js
vendored
6217
pagesmeeting/debug/lib-generate-test-usersig-es.min.js
vendored
File diff suppressed because it is too large
Load Diff
@ -82,6 +82,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</swiper-item>
|
</swiper-item>
|
||||||
</swiper>
|
</swiper>
|
||||||
|
|
||||||
<view class="bottom-box">
|
<view class="bottom-box">
|
||||||
<view class="bottom-btns">
|
<view class="bottom-btns">
|
||||||
<view class="btn-normal" @click="_pusherAudioHandler">
|
<view class="btn-normal" @click="_pusherAudioHandler">
|
||||||
@ -107,6 +108,34 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- <view class="panel memberlist-panel" v-if="show_memberList">
|
||||||
|
<view @click="_handleClose" class='close-btn'>X</view>
|
||||||
|
<view class="panel-header">成员列表</view>
|
||||||
|
<view class="panel-body">
|
||||||
|
<view class="panel-tips" v-if="playerList.length == 0">暂无成员</view>
|
||||||
|
<scroll-view class="scroll-container" scroll-y="true">
|
||||||
|
<view v-for="(items, index) in playerList" :key="index">
|
||||||
|
<view class="member-item" v-for="(item, streamID) in items" :key="streamID">
|
||||||
|
<view class="member-id">{{ item.userID }}</view>
|
||||||
|
<view class="member-btns">
|
||||||
|
<view class="btn">
|
||||||
|
<image class="audio-image" @click="_mutePlayerAudio(item)"
|
||||||
|
:src="item.muteAudio? require('../static/images/mute-mic-white.png') : require('../static/images/micro-open.png')">
|
||||||
|
</image>
|
||||||
|
</view>
|
||||||
|
<view class="btn">
|
||||||
|
<image class="audio-image" @click="_mutePlayerVideo(item)"
|
||||||
|
:src="item.muteVideo? require('../static/images/mute-camera-white.png') : require('../static/images/camera.png')">
|
||||||
|
</image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
</view> -->
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
@ -119,7 +148,7 @@
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
RtcConfig: {
|
RtcConfig: {
|
||||||
sdkAppID: '1600006944', // 必要参数 开通实时音视频服务创建应用后分配的 sdkAppID
|
sdkAppID: '', // 必要参数 开通实时音视频服务创建应用后分配的 sdkAppID
|
||||||
userID: '', // 必要参数 用户 ID 可以由您的帐号系统指定
|
userID: '', // 必要参数 用户 ID 可以由您的帐号系统指定
|
||||||
userSig: '', // 必要参数 身份签名,相当于登录密码的作用
|
userSig: '', // 必要参数 身份签名,相当于登录密码的作用
|
||||||
},
|
},
|
||||||
@ -151,20 +180,6 @@
|
|||||||
keepScreenOn: true,
|
keepScreenOn: true,
|
||||||
})
|
})
|
||||||
this.TRTC = new TRTC(this)
|
this.TRTC = new TRTC(this)
|
||||||
this.TRTC.setLocalVideoView({
|
|
||||||
streamType: TUIVideoStreamType.kCameraStream,
|
|
||||||
view: 'preview-camera',
|
|
||||||
});
|
|
||||||
// case 1: 桌面端打开摄像头
|
|
||||||
this.TRTC.openLocalCamera();
|
|
||||||
// case 2: 移动端使用前置摄像头打开视频预览
|
|
||||||
this.TRTC.openLocalCamera({
|
|
||||||
isFrontCamera: true
|
|
||||||
});
|
|
||||||
// case 3: 移动端使用后置摄像头打开视频预览
|
|
||||||
this.TRTC.openLocalCamera({
|
|
||||||
isFrontCamera: false
|
|
||||||
});
|
|
||||||
// 将String 类型的 true false 转换成 boolean
|
// 将String 类型的 true false 转换成 boolean
|
||||||
Object.getOwnPropertyNames(options).forEach((key) => {
|
Object.getOwnPropertyNames(options).forEach((key) => {
|
||||||
if (options[key] === 'true') {
|
if (options[key] === 'true') {
|
||||||
@ -189,16 +204,21 @@
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
init(options) {
|
init(options) {
|
||||||
|
|
||||||
|
console.log("options", options)
|
||||||
// pusher 初始化参数
|
// pusher 初始化参数
|
||||||
const pusherConfig = {
|
const pusherConfig = {
|
||||||
beautyLevel: 9,
|
beautyLevel: 9,
|
||||||
}
|
}
|
||||||
const pusher = this.TRTC.createPusher(pusherConfig)
|
const pusher = this.TRTC.createPusher(pusherConfig)
|
||||||
console.log("pusher", pusher)
|
console.log("pusher", pusher)
|
||||||
|
console.log('userID', this.RtcConfig)
|
||||||
this.RtcConfig.userID = options.userID;
|
this.RtcConfig.userID = options.userID;
|
||||||
this.RtcConfig.sdkAppID = '1600006944';
|
this.RtcConfig.sdkAppID = '1600006944';
|
||||||
this.RtcConfig.userSig = options.userSig;
|
this.RtcConfig.userSig = options.userSig;
|
||||||
this.pusher = pusher.pusherAttributes;
|
this.pusher = pusher.pusherAttributes;
|
||||||
|
console.log(this.localAudio, this.localVideo)
|
||||||
|
console.log("000000000000000")
|
||||||
},
|
},
|
||||||
|
|
||||||
enterRoom(options) {
|
enterRoom(options) {
|
||||||
@ -206,22 +226,24 @@
|
|||||||
const config = Object.assign(this.RtcConfig, {
|
const config = Object.assign(this.RtcConfig, {
|
||||||
roomID
|
roomID
|
||||||
})
|
})
|
||||||
console.log(config)
|
|
||||||
this.pusher = this.TRTC.enterRoom(config);
|
this.pusher = this.TRTC.enterRoom(config);
|
||||||
console.log("this.pusher", this.pusher)
|
console.log("this.pusher", this.pusher)
|
||||||
if (this.pusher) {
|
if (this.pusher) {
|
||||||
this.TRTC.getPusherInstance().start() // 开始推流
|
this.TRTC.getPusherInstance().start() // 开始推流
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
exitRoom() {
|
exitRoom() {
|
||||||
const result = this.TRTC.exitRoom();
|
const result = this.TRTC.exitRoom();
|
||||||
this.pusher = result.pusher;
|
this.pusher = result.pusher;
|
||||||
this.playerList = this.sliceIntoChunks(result.playerList, 2);
|
this.playerList = this.sliceIntoChunks(result.playerList, 2);
|
||||||
},
|
},
|
||||||
|
|
||||||
// 设置 pusher 属性
|
// 设置 pusher 属性
|
||||||
setPusherAttributesHandler(options) {
|
setPusherAttributesHandler(options) {
|
||||||
this.pusher = this.TRTC.setPusherAttributes(options);
|
this.pusher = this.TRTC.setPusherAttributes(options);
|
||||||
},
|
},
|
||||||
|
|
||||||
// 设置某个 player 属性
|
// 设置某个 player 属性
|
||||||
setPlayerAttributesHandler(player, options) {
|
setPlayerAttributesHandler(player, options) {
|
||||||
console.log("123", player, options, )
|
console.log("123", player, options, )
|
||||||
@ -236,11 +258,17 @@
|
|||||||
console.log("xxxxxxxxxxxx", TRTC_EVENT)
|
console.log("xxxxxxxxxxxx", TRTC_EVENT)
|
||||||
// 初始化事件订阅
|
// 初始化事件订阅
|
||||||
this.TRTC.on(TRTC_EVENT.LOCAL_JOIN, (event) => {
|
this.TRTC.on(TRTC_EVENT.LOCAL_JOIN, (event) => {
|
||||||
console.log('xxxxxxxxxxxxxxxxxxxxxxxxxxx', event)
|
console.log('* room LOCAL_JOIN', event)
|
||||||
|
if (this.localVideo) {
|
||||||
|
this.setPusherAttributesHandler({
|
||||||
|
enableCamera: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (this.localAudio) {
|
||||||
this.setPusherAttributesHandler({
|
this.setPusherAttributesHandler({
|
||||||
enableCamera: true,
|
|
||||||
enableMic: true
|
enableMic: true
|
||||||
})
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
this.TRTC.on(TRTC_EVENT.LOCAL_LEAVE, (event) => {
|
this.TRTC.on(TRTC_EVENT.LOCAL_LEAVE, (event) => {
|
||||||
console.log('* room LOCAL_LEAVE', event)
|
console.log('* room LOCAL_LEAVE', event)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user