更新分组密码
This commit is contained in:
parent
dfd308873a
commit
26e42dd2a4
@ -26,6 +26,7 @@ class GoodsGroupController extends AdminController
|
||||
$grid->column('id')->sortable();
|
||||
$grid->column('gp_name')->editable();
|
||||
$grid->column('is_open')->switch();
|
||||
$grid->column('is_open_group_pwd')->switch();
|
||||
$grid->column('ord')->editable();
|
||||
$grid->column('created_at');
|
||||
$grid->column('updated_at')->sortable();
|
||||
@ -66,6 +67,16 @@ class GoodsGroupController extends AdminController
|
||||
return admin_trans('dujiaoka.status_close');
|
||||
}
|
||||
});
|
||||
$show->field('is_open_group_pwd')->as(function ($isOpenGroupPwd) {
|
||||
if ($isOpenGroupPwd == GoodsGroupModel::STATUS_OPEN) {
|
||||
return admin_trans('dujiaoka.status_open');
|
||||
} else {
|
||||
return admin_trans('dujiaoka.status_close');
|
||||
}
|
||||
});
|
||||
$show->field('group_pwd')->as(function ($groupPwd) {
|
||||
return empty($groupPwd) ? '' : '******';
|
||||
});
|
||||
$show->field('ord');
|
||||
$show->field('created_at');
|
||||
$show->field('updated_at');
|
||||
@ -83,6 +94,8 @@ class GoodsGroupController extends AdminController
|
||||
$form->display('id');
|
||||
$form->text('gp_name');
|
||||
$form->switch('is_open')->default(GoodsGroupModel::STATUS_OPEN);
|
||||
$form->switch('is_open_group_pwd')->default(GoodsGroupModel::STATUS_CLOSE);
|
||||
$form->text('group_pwd')->help(admin_trans('goods-group.fields.group_pwd_help'));
|
||||
$form->number('ord')->default(1)->help(admin_trans('dujiaoka.ord'));
|
||||
$form->display('created_at');
|
||||
$form->display('updated_at');
|
||||
|
||||
@ -65,6 +65,7 @@ class HomeController extends BaseController
|
||||
try {
|
||||
$goods = $this->goodsService->detail($id);
|
||||
$this->goodsService->validatorGoodsStatus($goods);
|
||||
$this->goodsService->validatorGoodsGroupAccess($goods);
|
||||
// 有没有优惠码可以展示
|
||||
if (count($goods->coupon)) {
|
||||
$goods->open_coupon = 1;
|
||||
@ -83,6 +84,26 @@ class HomeController extends BaseController
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证商品分类访问密码
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function verifyGroupPassword(Request $request)
|
||||
{
|
||||
try {
|
||||
$request->validate([
|
||||
'group_id' => 'required|integer',
|
||||
'password' => 'required|string',
|
||||
]);
|
||||
$this->goodsService->verifyGroupPassword((int) $request->input('group_id'), (string) $request->input('password'));
|
||||
return response()->json(['code' => 200, 'msg' => __('dujiaoka.prompt.goods_group_password_success')]);
|
||||
} catch (RuleValidationException $ruleValidationException) {
|
||||
return response()->json(['code' => 400, 'msg' => $ruleValidationException->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 极验行为验证
|
||||
*
|
||||
|
||||
@ -17,6 +17,14 @@ class GoodsGroup extends BaseModel
|
||||
'deleted' => GoodsGroupDeleted::class
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
'group_pwd',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'is_open_group_pwd' => 'integer',
|
||||
];
|
||||
|
||||
/**
|
||||
* 关联商品
|
||||
*
|
||||
|
||||
@ -40,6 +40,7 @@ class GoodsService
|
||||
public function withGroup(): ?array
|
||||
{
|
||||
$goods = GoodsGroup::query()
|
||||
->select(['id', 'gp_name', 'is_open', 'is_open_group_pwd', 'group_pwd', 'ord', 'created_at', 'updated_at', 'deleted_at'])
|
||||
->with(['goods' => function($query) {
|
||||
$query->withCount(['carmis' => function($query) {
|
||||
$query->where('status', Carmis::STATUS_UNSOLD);
|
||||
@ -48,6 +49,15 @@ class GoodsService
|
||||
->where('is_open', GoodsGroup::STATUS_OPEN)
|
||||
->orderBy('ord', 'DESC')
|
||||
->get();
|
||||
|
||||
$goods->each(function (GoodsGroup $group) {
|
||||
$isLocked = $this->isGroupPasswordProtected($group) && !$this->hasGroupAccess($group->id);
|
||||
$group->setAttribute('is_group_locked', $isLocked ? GoodsGroup::STATUS_OPEN : GoodsGroup::STATUS_CLOSE);
|
||||
if ($isLocked) {
|
||||
$group->setRelation('goods', collect());
|
||||
}
|
||||
});
|
||||
|
||||
// 将自动
|
||||
return $goods ? $goods->toArray() : null;
|
||||
}
|
||||
@ -65,13 +75,98 @@ class GoodsService
|
||||
public function detail(int $id)
|
||||
{
|
||||
$goods = Goods::query()
|
||||
->with(['coupon'])
|
||||
->with(['coupon', 'group'])
|
||||
->withCount(['carmis' => function($query) {
|
||||
$query->where('status', Carmis::STATUS_UNSOLD);
|
||||
}])->where('id', $id)->first();
|
||||
return $goods;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分类是否开启密码访问
|
||||
*
|
||||
* @param GoodsGroup|null $group
|
||||
* @return bool
|
||||
*/
|
||||
public function isGroupPasswordProtected(?GoodsGroup $group): bool
|
||||
{
|
||||
return !empty($group)
|
||||
&& $group->is_open_group_pwd == GoodsGroup::STATUS_OPEN
|
||||
&& !empty($group->group_pwd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前会话是否已解锁分类
|
||||
*
|
||||
* @param int $groupID 分类id
|
||||
* @return bool
|
||||
*/
|
||||
public function hasGroupAccess(int $groupID): bool
|
||||
{
|
||||
$groupIDs = session('dujiaoka_group_pwd_access', []);
|
||||
return in_array($groupID, $groupIDs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证分类访问密码
|
||||
*
|
||||
* @param int $groupID 分类id
|
||||
* @param string $password 访问密码
|
||||
* @return bool
|
||||
*/
|
||||
public function verifyGroupPassword(int $groupID, string $password): bool
|
||||
{
|
||||
$group = GoodsGroup::query()
|
||||
->where('is_open', GoodsGroup::STATUS_OPEN)
|
||||
->where('id', $groupID)
|
||||
->first();
|
||||
|
||||
if (empty($group)) {
|
||||
throw new RuleValidationException(__('dujiaoka.prompt.goods_group_does_not_exist'));
|
||||
}
|
||||
|
||||
if (!$this->isGroupPasswordProtected($group)) {
|
||||
$this->grantGroupAccess($group->id);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!hash_equals((string) $group->group_pwd, (string) $password)) {
|
||||
throw new RuleValidationException(__('dujiaoka.prompt.goods_group_password_error'));
|
||||
}
|
||||
|
||||
$this->grantGroupAccess($group->id);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证商品所属分类访问权限
|
||||
*
|
||||
* @param Goods $goods 商品模型
|
||||
* @return void
|
||||
*/
|
||||
public function validatorGoodsGroupAccess(Goods $goods): void
|
||||
{
|
||||
$group = $goods->group;
|
||||
if ($this->isGroupPasswordProtected($group) && !$this->hasGroupAccess($group->id)) {
|
||||
throw new RuleValidationException(__('dujiaoka.prompt.goods_group_password_required'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 授权当前会话访问分类
|
||||
*
|
||||
* @param int $groupID 分类id
|
||||
* @return void
|
||||
*/
|
||||
private function grantGroupAccess(int $groupID): void
|
||||
{
|
||||
$groupIDs = session('dujiaoka_group_pwd_access', []);
|
||||
if (!in_array($groupID, $groupIDs)) {
|
||||
$groupIDs[] = $groupID;
|
||||
session(['dujiaoka_group_pwd_access' => $groupIDs]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化商品信息
|
||||
*
|
||||
|
||||
@ -106,6 +106,8 @@ class OrderService
|
||||
$goods = $this->goodsService->detail($request->input('gid'));
|
||||
// 商品状态验证
|
||||
$this->goodsService->validatorGoodsStatus($goods);
|
||||
// 商品所属分类访问权限验证
|
||||
$this->goodsService->validatorGoodsGroupAccess($goods);
|
||||
// 如果有限购
|
||||
if ($goods->buy_limit_num > 0 && $request->input('by_amount') > $goods->buy_limit_num) {
|
||||
throw new RuleValidationException(__('dujiaoka.prompt.purchase_limit_exceeded'));
|
||||
|
||||
34
public/assets/luna/main.js
vendored
34
public/assets/luna/main.js
vendored
@ -52,9 +52,37 @@
|
||||
if (typeof goodsMsg !== 'undefined' && goodsMsg !== '') {
|
||||
let cateTpl = document.getElementById('cateTpl').innerHTML, cateHtml = '';
|
||||
let goodsTpl = document.getElementById('goodsTpl').innerHTML, goodsHtml;
|
||||
let changeCate = function (key) {
|
||||
let showGroupPassword = function (group) {
|
||||
layer.prompt({
|
||||
title : (typeof groupPasswordTitle !== 'undefined' ? groupPasswordTitle : '请输入分类访问密码') + ':' + group.gp_name,
|
||||
formType: 1
|
||||
}, function (value, index) {
|
||||
$.post(groupPasswordVerifyUrl, {
|
||||
_token : groupPasswordCsrfToken,
|
||||
group_id: group.id,
|
||||
password: value
|
||||
}, function (res) {
|
||||
if (res.code === 200) {
|
||||
layer.close(index);
|
||||
window.location.reload();
|
||||
} else {
|
||||
layer.msg(res.msg);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
let changeCate = function (key, silent) {
|
||||
let group = goodsMsg[key];
|
||||
if (group.is_group_locked) {
|
||||
$('.goods-list').empty();
|
||||
$('.cate-box').removeClass('cate-box-select').eq(key).addClass('cate-box-select');
|
||||
if (!silent) {
|
||||
showGroupPassword(group);
|
||||
}
|
||||
return;
|
||||
}
|
||||
goodsHtml = '';
|
||||
goodsMsg[key].goods.forEach(function (i) {
|
||||
group.goods.forEach(function (i) {
|
||||
if (i.wholesale_price_cnf != "" && i.wholesale_price_cnf != null) {
|
||||
i.wholesale_price_arr = i.wholesale_price_cnf.split("\r\n");
|
||||
i.wholesale_price_arr.forEach(function (ii, k) {
|
||||
@ -79,7 +107,7 @@
|
||||
$('.cate').empty().append(cateHtml).on('click', '.cate-box', function () {
|
||||
changeCate($(this).data('key'));
|
||||
});
|
||||
changeCate(0);
|
||||
changeCate(0, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -124,7 +124,15 @@ return [
|
||||
'no_related_order_found_for_cache' => '未找到相关订单缓存!',
|
||||
'no_related_order_found' => '未找到相关订单!',
|
||||
'new_order_push' => '新订单通知',
|
||||
'loop_carmis_limit' => '此商品最多购买一件!'
|
||||
'loop_carmis_limit' => '此商品最多购买一件!',
|
||||
'goods_group_does_not_exist' => '商品分类不存在',
|
||||
'goods_group_password_error' => '分类访问密码错误',
|
||||
'goods_group_password_required' => '请先输入分类访问密码',
|
||||
'goods_group_password_required_short' => '密码访问',
|
||||
'goods_group_password_title' => '分类密码访问',
|
||||
'goods_group_password_placeholder' => '请输入分类访问密码',
|
||||
'goods_group_password_submit' => '确认进入',
|
||||
'goods_group_password_success' => '验证成功'
|
||||
],
|
||||
|
||||
'equipment' => [
|
||||
|
||||
@ -8,6 +8,9 @@ return [
|
||||
'fields' => [
|
||||
'gp_name' => '分类名称',
|
||||
'is_open' => '是否启用',
|
||||
'is_open_group_pwd' => '开启密码访问',
|
||||
'group_pwd' => '访问密码',
|
||||
'group_pwd_help' => '开启密码访问后,前台需要输入此密码才可查看该分类商品',
|
||||
'ord' => '排序权重 越大越靠前',
|
||||
],
|
||||
'options' => [
|
||||
|
||||
@ -123,7 +123,16 @@ return [
|
||||
'search_order_browser_tips' => '最多只能查詢最近 5 筆訂單',
|
||||
'no_related_order_found_for_cache' => '未找到相關訂單快取!',
|
||||
'no_related_order_found' => '未找到相關訂單!',
|
||||
'new_order_push' => '新訂單通知'
|
||||
'new_order_push' => '新訂單通知',
|
||||
'loop_carmis_limit' => '此商品最多購買一件!',
|
||||
'goods_group_does_not_exist' => '商品分類不存在',
|
||||
'goods_group_password_error' => '分類訪問密碼錯誤',
|
||||
'goods_group_password_required' => '請先輸入分類訪問密碼',
|
||||
'goods_group_password_required_short' => '密碼訪問',
|
||||
'goods_group_password_title' => '分類密碼訪問',
|
||||
'goods_group_password_placeholder' => '請輸入分類訪問密碼',
|
||||
'goods_group_password_submit' => '確認進入',
|
||||
'goods_group_password_success' => '驗證成功'
|
||||
],
|
||||
|
||||
'equipment' => [
|
||||
|
||||
@ -8,6 +8,9 @@ return [
|
||||
'fields' => [
|
||||
'gp_name' => '分類名稱',
|
||||
'is_open' => '是否啟用',
|
||||
'is_open_group_pwd' => '開啟密碼訪問',
|
||||
'group_pwd' => '訪問密碼',
|
||||
'group_pwd_help' => '開啟密碼訪問後,前台需要輸入此密碼才可查看該分類商品',
|
||||
'ord' => '排序權重 越大越靠前',
|
||||
],
|
||||
'options' => [
|
||||
|
||||
@ -32,9 +32,16 @@
|
||||
</div>
|
||||
</a>
|
||||
@foreach($data as $index => $group)
|
||||
@if(!empty($group['is_group_locked']))
|
||||
<a href="javascript:void(0);" class="tab-link group-password-link" data-group-id="{{ $group['id'] }}" data-group-name="{{ $group['gp_name'] }}" aria-expanded="false" role="tab">
|
||||
@else
|
||||
<a href="#group-{{ $group['id'] }}" class="tab-link" data-bs-toggle="tab" aria-expanded="false" role="tab" data-toggle="tab">
|
||||
@endif
|
||||
<span class="tab-title">
|
||||
{{ $group['gp_name'] }}
|
||||
@if(!empty($group['is_group_locked']))
|
||||
<i class="uil-lock-alt"></i>
|
||||
@endif
|
||||
</span>
|
||||
<div class="img-checkmark">
|
||||
<img src="/assets/hyper/images/check.png">
|
||||
@ -98,6 +105,24 @@
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
<div class="modal fade" id="group-password-modal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ __('dujiaoka.prompt.goods_group_password_title') }}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="group-password-id">
|
||||
<div class="mb-2" id="group-password-name"></div>
|
||||
<input type="password" class="form-control" id="group-password-input" placeholder="{{ __('dujiaoka.prompt.goods_group_password_placeholder') }}">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" id="group-password-submit">{{ __('dujiaoka.prompt.goods_group_password_submit') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="notice-modal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
@ -125,8 +150,29 @@
|
||||
$(".category").show();
|
||||
}
|
||||
});
|
||||
$('.group-password-link').click(function() {
|
||||
$('#group-password-id').val($(this).data('group-id'));
|
||||
$('#group-password-name').text($(this).data('group-name'));
|
||||
$('#group-password-input').val('');
|
||||
$('#group-password-modal').modal();
|
||||
});
|
||||
|
||||
$('#group-password-submit').click(function() {
|
||||
$.post("{{ url('verify-group-password') }}", {
|
||||
_token: "{{ csrf_token() }}",
|
||||
group_id: $('#group-password-id').val(),
|
||||
password: $('#group-password-input').val()
|
||||
}, function(res) {
|
||||
if (res.code === 200) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
$.NotificationApp.send("{{ __('hyper.home_tip') }}", res.msg, "top-center", "rgba(0,0,0,0.2)", "error");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function sell_out_tip() {
|
||||
$.NotificationApp.send("{{ __('hyper.home_tip') }}","{{ __('hyper.home_sell_out_tip') }}","top-center","rgba(0,0,0,0.2)","info");
|
||||
}
|
||||
</script>
|
||||
@stop
|
||||
@stop
|
||||
|
||||
@ -73,8 +73,8 @@
|
||||
</body>
|
||||
<script id="cateTpl" type="text/html">
|
||||
<div class="cate-box" data-key="<< d.key >>">
|
||||
<p><< d.gp_name >></p>
|
||||
<div>{{ __('luna.goods_num') }}:<< d.goods.length >></div>
|
||||
<p><< d.gp_name >><<# if(d.is_group_locked){ >> 🔒<<# }; >></p>
|
||||
<div><<# if(d.is_group_locked){ >>{{ __('dujiaoka.prompt.goods_group_password_required_short') }}<<# } else { >>{{ __('luna.goods_num') }}:<< d.goods.length >><<# }; >></div>
|
||||
</div>
|
||||
</script>
|
||||
<script id="goodsTpl" type="text/html">
|
||||
@ -101,8 +101,12 @@
|
||||
</script>
|
||||
|
||||
<script>
|
||||
let title = "{{ __('dujiaoka.site_announcement') }}",
|
||||
goodsMsg = {!! json_encode($data) !!};
|
||||
let title = "{{ __('dujiaoka.site_announcement') }}",
|
||||
goodsMsg = {!! json_encode($data) !!},
|
||||
groupPasswordVerifyUrl = "{{ url('verify-group-password') }}",
|
||||
groupPasswordCsrfToken = "{{ csrf_token() }}",
|
||||
groupPasswordTitle = "{{ __('dujiaoka.prompt.goods_group_password_title') }}",
|
||||
groupPasswordPlaceholder = "{{ __('dujiaoka.prompt.goods_group_password_placeholder') }}",
|
||||
groupPasswordSubmit = "{{ __('dujiaoka.prompt.goods_group_password_submit') }}";
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
|
||||
@ -48,7 +48,11 @@
|
||||
</li>
|
||||
@foreach($data as $index => $group)
|
||||
<li class="nav-item">
|
||||
<a href="#group-{{ $group['id'] }}" data-bs-toggle="tab" class="btn btn-outline-secondary">{{ $group['gp_name'] }}</a>
|
||||
@if(!empty($group['is_group_locked']))
|
||||
<a href="javascript:void(0);" class="btn btn-outline-secondary group-password-link" data-group-id="{{ $group['id'] }}" data-group-name="{{ $group['gp_name'] }}">{{ $group['gp_name'] }} <i class="ali-icon"></i></a>
|
||||
@else
|
||||
<a href="#group-{{ $group['id'] }}" data-bs-toggle="tab" class="btn btn-outline-secondary">{{ $group['gp_name'] }}</a>
|
||||
@endif
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@ -171,6 +175,25 @@
|
||||
</section>
|
||||
<!-- main end -->
|
||||
|
||||
<div class="modal fade" id="group-password-modal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ __('dujiaoka.prompt.goods_group_password_title') }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="group-password-id">
|
||||
<div class="mb-2" id="group-password-name"></div>
|
||||
<input type="password" class="form-control" id="group-password-input" placeholder="{{ __('dujiaoka.prompt.goods_group_password_placeholder') }}">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" id="group-password-submit">{{ __('dujiaoka.prompt.goods_group_password_submit') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@stop
|
||||
|
||||
@section('js')
|
||||
@ -185,5 +208,35 @@
|
||||
$(".col").show();
|
||||
}
|
||||
});
|
||||
|
||||
function showGroupPasswordModal() {
|
||||
var modalEl = document.getElementById('group-password-modal');
|
||||
if (typeof bootstrap !== 'undefined' && bootstrap.Modal) {
|
||||
bootstrap.Modal.getOrCreateInstance(modalEl).show();
|
||||
} else {
|
||||
$('#group-password-modal').modal();
|
||||
}
|
||||
}
|
||||
|
||||
$('.group-password-link').click(function() {
|
||||
$('#group-password-id').val($(this).data('group-id'));
|
||||
$('#group-password-name').text($(this).data('group-name'));
|
||||
$('#group-password-input').val('');
|
||||
showGroupPasswordModal();
|
||||
});
|
||||
|
||||
$('#group-password-submit').click(function() {
|
||||
$.post("{{ url('verify-group-password') }}", {
|
||||
_token: "{{ csrf_token() }}",
|
||||
group_id: $('#group-password-id').val(),
|
||||
password: $('#group-password-input').val()
|
||||
}, function(res) {
|
||||
if (res.code === 200) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert(res.msg);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@stop
|
||||
|
||||
@ -16,6 +16,8 @@ Route::group(['middleware' => ['dujiaoka.boot'],'namespace' => 'Home'], function
|
||||
Route::get('check-geetest', 'HomeController@geetest');
|
||||
// 商品详情
|
||||
Route::get('buy/{id}', 'HomeController@buy');
|
||||
// 验证商品分类访问密码
|
||||
Route::post('verify-group-password', 'HomeController@verifyGroupPassword');
|
||||
// 提交订单
|
||||
Route::post('create-order', 'OrderController@createOrder');
|
||||
// 结算页
|
||||
@ -40,4 +42,3 @@ Route::group(['middleware' => ['install.check'],'namespace' => 'Home'], function
|
||||
// 执行安装
|
||||
Route::post('do-install', 'HomeController@doInstall');
|
||||
});
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user