payment
This commit is contained in:
@@ -14,8 +14,6 @@ export enum PermissionEnum {
|
||||
UPDATE_INVOICE = 'update_invoice',
|
||||
DELETE_INVOICE = 'delete_invoice',
|
||||
|
||||
VIEW_All_INVOICED_ORDERS = 'view_all_invoiced_orders',
|
||||
VIEW_MY_ASSIGNED_INVOICED_REQUESTS = 'view_my_assigned_invoiced_requests',
|
||||
|
||||
VIEW_ORDERS = 'view_orders',
|
||||
VIEW_ASSIGNED_ORDERS = 'view_assigned_orders',
|
||||
@@ -31,9 +29,8 @@ export enum PermissionEnum {
|
||||
VIEW_USERS = 'view_users',
|
||||
|
||||
|
||||
// User & Admin Management
|
||||
MANAGE_ADMINS = 'manage_admins',
|
||||
// Role Management
|
||||
|
||||
MANAGE_ROLES = 'manage_roles',
|
||||
|
||||
|
||||
@@ -41,30 +38,21 @@ export enum PermissionEnum {
|
||||
|
||||
MANAGE_SETTINGS = 'manage_settings',
|
||||
|
||||
MANAGE_FORM_BUILDER = 'manage_form_builder',
|
||||
|
||||
CREATE_PRINT = 'create_print',
|
||||
|
||||
MANAGE_PRINT = 'view_print',
|
||||
VIEW_PRINT = 'view_print',
|
||||
|
||||
MANAGE_LEARNINGS = 'manage_learnings',
|
||||
|
||||
MANAGE_CRITICISMS = 'manage_criticisms',
|
||||
|
||||
MANAGE_ANNOUNCEMENTS = 'manage_announcements',
|
||||
|
||||
MANAGE_TICKETS = 'manage_tickets',
|
||||
|
||||
// Notif Permsissions
|
||||
NEW_REQUEST_NOTIFICATION='new_request_notification',
|
||||
|
||||
NEW_PAYMENT_NOTIFICATION='new_payment_notification',
|
||||
}
|
||||
|
||||
/**
|
||||
* Permission titles mapping (Farsi)
|
||||
* Maps permission names to their Farsi titles
|
||||
*/
|
||||
|
||||
export const PermissionTitles: Record<PermissionEnum, string> = {
|
||||
[PermissionEnum.MANAGE_PRODUCTS]: 'مدیریت محصولات',
|
||||
[PermissionEnum.MANAGE_CATEGORIES]: 'مدیریت دستهبندیها',
|
||||
@@ -79,10 +67,7 @@ export const PermissionTitles: Record<PermissionEnum, string> = {
|
||||
[PermissionEnum.MANAGE_ROLES]: 'مدیریت نقشها',
|
||||
[PermissionEnum.MANAGE_PAYMENTS]: 'مدیریت پرداختها',
|
||||
[PermissionEnum.MANAGE_SETTINGS]: 'مدیریت تنظیمات',
|
||||
[PermissionEnum.MANAGE_FORM_BUILDER]: "مدیریت فرم بیلدر",
|
||||
[PermissionEnum.VIEW_REQUESTS]: "مشاهده همه درخواست سفارش ها",
|
||||
[PermissionEnum.VIEW_All_INVOICED_ORDERS]: "مشاهده همه سفارشات پیش فاکتور شده",
|
||||
[PermissionEnum.VIEW_MY_ASSIGNED_INVOICED_REQUESTS]: "مشاهده همه پیش فاکتور های من",
|
||||
[PermissionEnum.DELETE_REQUEST]: "",
|
||||
[PermissionEnum.UPDATE_REQUEST]: "",
|
||||
[PermissionEnum.VIEW_INVOICES]: "",
|
||||
@@ -91,7 +76,7 @@ export const PermissionTitles: Record<PermissionEnum, string> = {
|
||||
[PermissionEnum.DELETE_INVOICE]: "",
|
||||
[PermissionEnum.DELETE_ORDER]: "",
|
||||
[PermissionEnum.CREATE_PRINT]: "ایجاد فرم چاپ برای سفارش",
|
||||
[PermissionEnum.MANAGE_PRINT]: "مدیریت فرم چاپ",
|
||||
[PermissionEnum.VIEW_PRINT]: "مدیریت فرم چاپ",
|
||||
[PermissionEnum.MANAGE_LEARNINGS]: "مدیریت آموزشها",
|
||||
[PermissionEnum.MANAGE_CRITICISMS]: "مدیریت انتقادها و پیشنهادها",
|
||||
[PermissionEnum.MANAGE_ANNOUNCEMENTS]: "مدیریت اطلاعیهها",
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Controller, Post, Body, Get, UseGuards, Patch, Param, Delete } from '@n
|
||||
import { AdminService } from '../providers/admin.service';
|
||||
import { CreateAdminDto } from '../dto/create-admin.dto';
|
||||
import { UpdateAdminDto } from '../dto/update-admin.dto';
|
||||
import { ApiTags, ApiOperation, ApiBody, ApiBearerAuth, ApiParam } from '@nestjs/swagger';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard';
|
||||
import { AdminId } from 'src/common/decorators/admin-id.decorator';
|
||||
import { Admin } from '../entities/admin.entity';
|
||||
@@ -13,11 +13,11 @@ import { Permissions } from 'src/common/decorators/permissions.decorator';
|
||||
@ApiTags('admin')
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@Permissions(PermissionEnum.MANAGE_ADMINS)
|
||||
export class AdminController {
|
||||
constructor(private readonly adminService: AdminService) { }
|
||||
|
||||
@Post('admin/admin')
|
||||
@Permissions(PermissionEnum.MANAGE_ADMINS)
|
||||
@ApiOperation({ summary: 'Create a new admin' })
|
||||
async create(@Body() dto: CreateAdminDto,) {
|
||||
const admin = await this.adminService.create(dto);
|
||||
@@ -25,13 +25,20 @@ export class AdminController {
|
||||
}
|
||||
|
||||
@Get('admin/admins')
|
||||
@Permissions(PermissionEnum.MANAGE_ADMINS)
|
||||
@ApiOperation({ summary: 'admin' })
|
||||
async getAll() {
|
||||
const admin = await this.adminService.findAll();
|
||||
return admin;
|
||||
getAll() {
|
||||
return this.adminService.findAll();
|
||||
}
|
||||
|
||||
@Get('admin/admins/search')
|
||||
@ApiOperation({ summary: 'get admin list , has no permission' })
|
||||
searchAll() {
|
||||
return this.adminService.findAll();
|
||||
}
|
||||
|
||||
@Get('admin/admins/me')
|
||||
@Permissions(PermissionEnum.MANAGE_ADMINS)
|
||||
@ApiOperation({ summary: 'admin' })
|
||||
async getMe(@AdminId() adminId: string,) {
|
||||
const admin = await this.adminService.findById(adminId,);
|
||||
@@ -40,18 +47,21 @@ export class AdminController {
|
||||
|
||||
|
||||
@Patch('admin/admins/:adminId')
|
||||
@Permissions(PermissionEnum.MANAGE_ADMINS)
|
||||
@ApiOperation({ summary: 'Update an admin' })
|
||||
update(@Param('adminId') adminId: string, @Body() dto: UpdateAdminDto,): Promise<Admin> {
|
||||
return this.adminService.update(adminId, dto);
|
||||
}
|
||||
|
||||
@Get('admin/admins/:adminId')
|
||||
@Permissions(PermissionEnum.MANAGE_ADMINS)
|
||||
@ApiOperation({ summary: 'Get an admin by ID' })
|
||||
getById(@Param('adminId') adminId: string,): Promise<Admin | null> {
|
||||
return this.adminService.findById(adminId,);
|
||||
}
|
||||
|
||||
@Delete('admin/admins/:adminId')
|
||||
@Permissions(PermissionEnum.MANAGE_ADMINS)
|
||||
@ApiOperation({ summary: 'Delete an admin by ID' })
|
||||
deleteById(@Param('adminId') adminId: string,): Promise<void> {
|
||||
return this.adminService.softDelete(adminId,);
|
||||
|
||||
@@ -8,8 +8,6 @@ import { FieldOptionService } from '../provider/field-option.service';
|
||||
import { UpdateFieldDto } from '../dto/update-field.dto';
|
||||
import { UpdateFieldOptionDto } from '../dto/update-field-option.dto';
|
||||
import { FindFieldsGroupDto } from '../dto/find-field-group.dto';
|
||||
import { Permissions } from 'src/common/decorators/permissions.decorator';
|
||||
import { PermissionEnum } from 'src/common/enums/permission.enum';
|
||||
|
||||
@Controller()
|
||||
@ApiBearerAuth()
|
||||
@@ -31,7 +29,6 @@ export class FormBuilderController {
|
||||
// ============= Admin =================
|
||||
@Post('admin/entity/:id/field')
|
||||
@ApiOperation({ summary: 'Create field for entity' })
|
||||
@Permissions(PermissionEnum.MANAGE_FORM_BUILDER)
|
||||
@UseGuards(AdminAuthGuard)
|
||||
createField(@Body() dto: CreateFieldDto, @Param('id') entityId: string) {
|
||||
return this.fieldService.create(entityId, dto);
|
||||
@@ -61,7 +58,6 @@ export class FormBuilderController {
|
||||
@Patch('admin/entity/field/:id')
|
||||
@ApiOperation({ summary: 'Update field' })
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.MANAGE_FORM_BUILDER)
|
||||
updateField(@Param('id') id: string, @Body() dto: UpdateFieldDto) {
|
||||
return this.fieldService.update(id, dto);
|
||||
}
|
||||
@@ -69,7 +65,6 @@ export class FormBuilderController {
|
||||
@Delete('admin/entity/field/:id')
|
||||
@ApiOperation({ summary: 'Remove field' })
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.MANAGE_FORM_BUILDER)
|
||||
removeField(@Param('id') id: string) {
|
||||
return this.fieldService.remove(id);
|
||||
}
|
||||
@@ -79,7 +74,6 @@ export class FormBuilderController {
|
||||
@Post('admin/entity/field/:id/option')
|
||||
@ApiOperation({ summary: 'Create field Options ' })
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.MANAGE_FORM_BUILDER)
|
||||
createFieldOption(@Body() dto: CreateFieldOptionDto, @Param('id') id: string) {
|
||||
return this.fieldOptionService.create(id, dto);
|
||||
}
|
||||
@@ -101,7 +95,6 @@ export class FormBuilderController {
|
||||
@Patch('admin/entity/field/option/:id')
|
||||
@ApiOperation({ summary: 'Update field Option' })
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.MANAGE_FORM_BUILDER)
|
||||
updateFieldOption(@Param('id') id: string, @Body() dto: UpdateFieldOptionDto) {
|
||||
return this.fieldOptionService.update(id, dto);
|
||||
}
|
||||
@@ -109,7 +102,6 @@ export class FormBuilderController {
|
||||
@Delete('admin/entity/field/option/:id')
|
||||
@ApiOperation({ summary: 'Renopve field Option' })
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.MANAGE_FORM_BUILDER)
|
||||
removeFieldOption(@Param('id') id: string) {
|
||||
return this.fieldOptionService.remove(id);
|
||||
}
|
||||
|
||||
@@ -50,12 +50,14 @@ export class InvoiceController {
|
||||
@Get('admin/invoice')
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@ApiOperation({ summary: 'Get all invoices with pagination and filters' })
|
||||
@Permissions(PermissionEnum.VIEW_INVOICES)
|
||||
findAllAsAdmin(@Query() dto: FindInvoicesDto) {
|
||||
return this.invoiceService.findAllAsAdmin(dto);
|
||||
}
|
||||
|
||||
@Get('admin/invoice/:id')
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.VIEW_INVOICES)
|
||||
@ApiOperation({ summary: 'Get one invoice by id (admin)' })
|
||||
findOneAsAdmin(@Param('id') id: string) {
|
||||
return this.invoiceService.findOneAsAdmin(id);
|
||||
@@ -65,7 +67,7 @@ export class InvoiceController {
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.UPDATE_INVOICE)
|
||||
@ApiOperation({ summary: 'Update an invoice (admin)' })
|
||||
@ApiBody({ type: UpdateInvoiceDto })
|
||||
@Permissions(PermissionEnum.UPDATE_INVOICE)
|
||||
update(@Param('id') id: string, @Body() updateInvoiceDto: UpdateInvoiceDto) {
|
||||
return this.invoiceService.update(id, updateInvoiceDto);
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ export class OrderController {
|
||||
// Permission handled inside service
|
||||
@Get('admin/orders')
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.VIEW_ORDERS)
|
||||
@ApiOperation({ summary: 'Get all orders with pagination and filters' })
|
||||
findAllAsAdmin(@Query() dto: FindOrdersDto, @AdminId() adminId: string) {
|
||||
return this.orderService.findOrdersAsAdmin(adminId, dto);
|
||||
@@ -62,6 +63,7 @@ export class OrderController {
|
||||
|
||||
@Get('admin/orders/:id')
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.VIEW_ORDERS)
|
||||
@ApiOperation({ summary: 'order detail' })
|
||||
orderDetailAsAdmin(@Param('id') orderId: string) {
|
||||
return this.orderService.findOrderOrFail(orderId);
|
||||
@@ -112,6 +114,7 @@ export class OrderController {
|
||||
|
||||
@Get('admin/orders/:orderId/print')
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.VIEW_PRINT)
|
||||
@ApiOperation({ summary: 'Get order print' })
|
||||
getPrint(@Param('orderId') orderId: string) {
|
||||
return this.orderService.getPrint(orderId);
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
Query,
|
||||
Delete,
|
||||
} from '@nestjs/common';
|
||||
// import { PaymentService } from '../services/payments.service';
|
||||
import { PaymentService } from '../services/payments.service';
|
||||
import {
|
||||
ApiTags,
|
||||
ApiOperation,
|
||||
@@ -25,72 +25,72 @@ import { PermissionEnum } from 'src/common/enums/permission.enum';
|
||||
@Controller()
|
||||
export class PaymentController {
|
||||
constructor(
|
||||
// private readonly paymentService: PaymentService,
|
||||
private readonly paymentService: PaymentService,
|
||||
) { }
|
||||
|
||||
|
||||
// @Post('public/payments/order/:id/pay')
|
||||
// @UseGuards(AuthGuard)
|
||||
// @ApiOperation({ summary: 'Pay for an order' })
|
||||
// payAnOrder(@Param('id') orderId: string, @Body() dto: PayOrderDto) {
|
||||
// return this.paymentService.payOrder(orderId, dto);
|
||||
// }
|
||||
@Post('public/payments/invoice/:id/pay')
|
||||
@UseGuards(AuthGuard)
|
||||
@ApiOperation({ summary: 'Pay for an order' })
|
||||
payAnInvoice(@Param('id') invoiceId: string, @Body() dto: PayOrderDto) {
|
||||
return this.paymentService.payInvoice(invoiceId, dto);
|
||||
}
|
||||
|
||||
// @Post('public/payments/online/:token/verify')
|
||||
// @UseGuards(AuthGuard)
|
||||
// @ApiOperation({ summary: 'Verify online payment' })
|
||||
// verifyOnlinePayment(@Param('paymentId') token: string) {
|
||||
// return this.paymentService.verifyOnlinePayment(token);
|
||||
// }
|
||||
@Post('public/payments/online/:token/verify')
|
||||
@UseGuards(AuthGuard)
|
||||
@ApiOperation({ summary: 'Verify online payment' })
|
||||
verifyOnlinePayment(@Param('paymentId') token: string) {
|
||||
return this.paymentService.verifyOnlinePayment(token);
|
||||
}
|
||||
|
||||
|
||||
// @Get('public/payments')
|
||||
// @ApiOperation({ summary: 'get all payments as user' })
|
||||
// findAllByUser(@UserId() userId: string, @Query() dto: FindPaymentsDto) {
|
||||
// return this.paymentService.findAllByUser(dto, userId);
|
||||
// }
|
||||
@Get('public/payments')
|
||||
@ApiOperation({ summary: 'get all payments as user' })
|
||||
findAllByUser(@UserId() userId: string, @Query() dto: FindPaymentsDto) {
|
||||
return this.paymentService.findAllByUser(dto, userId);
|
||||
}
|
||||
|
||||
// /*=============== Admin =============== */
|
||||
/*=============== Admin =============== */
|
||||
|
||||
// @Post('admin/payments/order/:id/pay')
|
||||
// @UseGuards(AdminAuthGuard)
|
||||
// @Permissions(PermissionEnum.MANAGE_PAYMENTS)
|
||||
// @ApiOperation({ summary: 'Pay for an order as Admin' })
|
||||
// payOrderAsAdmin(@Param('orderId') orderId: string, @AdminId() adminId: string, @Body() dto: PayOrderDto) {
|
||||
// return this.paymentService.payOrder(orderId, dto, adminId);
|
||||
// }
|
||||
@Post('admin/payments/order/:id/pay')
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.MANAGE_PAYMENTS)
|
||||
@ApiOperation({ summary: 'Pay for an order as Admin' })
|
||||
payOrderAsAdmin(@Param('orderId') orderId: string, @AdminId() adminId: string, @Body() dto: PayOrderDto) {
|
||||
return this.paymentService.payInvoice(orderId, dto, adminId);
|
||||
}
|
||||
|
||||
// @Post('admin/payments/online/:token/verify')
|
||||
// @UseGuards(AdminAuthGuard)
|
||||
// @Permissions(PermissionEnum.MANAGE_PAYMENTS)
|
||||
// @ApiOperation({ summary: 'Verify online payment as admin' })
|
||||
// verifyOnlinePaymentAsAdmin(@Param('paymentId') token: string) {
|
||||
// return this.paymentService.verifyOnlinePayment(token);
|
||||
// }
|
||||
@Post('admin/payments/online/:token/verify')
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.MANAGE_PAYMENTS)
|
||||
@ApiOperation({ summary: 'Verify online payment as admin' })
|
||||
verifyOnlinePaymentAsAdmin(@Param('paymentId') token: string) {
|
||||
return this.paymentService.verifyOnlinePayment(token);
|
||||
}
|
||||
|
||||
// @Post('admin/payments/:paymentId/cash/verify')
|
||||
// @UseGuards(AdminAuthGuard)
|
||||
// @Permissions(PermissionEnum.MANAGE_PAYMENTS)
|
||||
// @ApiOperation({ summary: 'Verify cash payment' })
|
||||
// confirmPayment(@Param('paymentId') paymentId: string) {
|
||||
// return this.paymentService.confirmCashPayment(paymentId);
|
||||
// }
|
||||
@Post('admin/payments/:paymentId/cash/verify')
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.MANAGE_PAYMENTS)
|
||||
@ApiOperation({ summary: 'Verify cash payment' })
|
||||
confirmPayment(@Param('paymentId') paymentId: string) {
|
||||
return this.paymentService.confirmCashPayment(paymentId);
|
||||
}
|
||||
|
||||
// @Delete('admin/payments/:paymentId/cash/deny')
|
||||
// @UseGuards(AdminAuthGuard)
|
||||
// @Permissions(PermissionEnum.MANAGE_PAYMENTS)
|
||||
// @ApiOperation({ summary: 'Deny cash payment' })
|
||||
// denyPayment(@Param('paymentId') paymentId: string) {
|
||||
// return this.paymentService.denyCashPayment(paymentId);
|
||||
// }
|
||||
@Delete('admin/payments/:paymentId/cash/deny')
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.MANAGE_PAYMENTS)
|
||||
@ApiOperation({ summary: 'Deny cash payment' })
|
||||
denyPayment(@Param('paymentId') paymentId: string) {
|
||||
return this.paymentService.denyCashPayment(paymentId);
|
||||
}
|
||||
|
||||
|
||||
// @Get('admin/payments')
|
||||
// @UseGuards(AdminAuthGuard)
|
||||
// @Permissions(PermissionEnum.MANAGE_PAYMENTS)
|
||||
// @ApiOperation({ summary: 'get all payments as admin' })
|
||||
// findAllPayments(@Body() dto: FindPaymentsDto) {
|
||||
// return this.paymentService.findAll(dto);
|
||||
// }
|
||||
@Get('admin/payments')
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@Permissions(PermissionEnum.MANAGE_PAYMENTS)
|
||||
@ApiOperation({ summary: 'get all payments as admin' })
|
||||
findAllPayments(@Body() dto: FindPaymentsDto) {
|
||||
return this.paymentService.findAll(dto);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { PaymentGatewayEnum, PaymentMethodEnum, PaymentStatusEnum } from '../interface/payment';
|
||||
import { PaymentMethodEnum, PaymentStatusEnum } from '../interface/payment';
|
||||
import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { GatewayManager } from '../gateways/gateway.manager';
|
||||
import { OrderPaymentContext } from '../interface/payment';
|
||||
import { PaymentMessage, OrderMessage } from 'src/common/enums/message.enum';
|
||||
@@ -38,7 +38,7 @@ export class PaymentService {
|
||||
private readonly invoiceService: InvoiceService,
|
||||
) { }
|
||||
|
||||
async payOrder(invoiceId: string, dto: PayOrderDto, adminId?: string): Promise<{ paymentUrl: string | null }> {
|
||||
async payInvoice(invoiceId: string, dto: PayOrderDto, adminId?: string): Promise<{ paymentUrl: string | null }> {
|
||||
|
||||
const ctx = await this.loadAndValidateOrder(invoiceId, dto, adminId)
|
||||
|
||||
@@ -63,8 +63,7 @@ export class PaymentService {
|
||||
private async loadAndValidateOrder(invoiceId: string, dto: PayOrderDto, adminId?: string): Promise<OrderPaymentContext> {
|
||||
const { amount, method, attachments, description, gateway } = dto
|
||||
|
||||
// const order = await this.orderService.findOrderOrFail(invoiceId)
|
||||
const invoice=await this.invoiceService.findOneOrFail(invoiceId)
|
||||
const invoice = await this.invoiceService.findOneOrFail(invoiceId)
|
||||
|
||||
if (!invoice.balance) {
|
||||
throw new NotFoundException('Balance is not set');
|
||||
@@ -147,7 +146,7 @@ export class PaymentService {
|
||||
|
||||
await em.persistAndFlush([payment, newCreditTransaction]);
|
||||
});
|
||||
//TODO
|
||||
//TODO
|
||||
// this.eventEmitter.emit(
|
||||
// newCashPaymentEvent.name,
|
||||
// new newCashPaymentEvent(ctx.invoice.id, String(ctx.invoice?.invoiceNumber) || '', ctx.method, ctx.amount),
|
||||
|
||||
Reference in New Issue
Block a user