forked from slavaxom9k/PIBD-23_Fomichev_V.S._MagicCarpet
небольшие правки
This commit is contained in:
@@ -28,7 +28,7 @@ internal class EmployeeStorageContract : IEmployeeStorageContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<EmployeeDataModel> GetList(bool onlyActive = true, string? email = null, DateTime? fromBirthDate = null, DateTime? toBirthDate = null,
|
public List<EmployeeDataModel> GetList(bool onlyActive = true, string? email = null, DateTime? fromBirthDate = null, DateTime? toBirthDate = null,
|
||||||
DateTime? fromEmploymentDate = null, DateTime? toEmploymentDate = null)
|
DateTime? fromEmploymentDate = null, DateTime? toEmploymentDate = null, string postId = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ internal class Tour
|
|||||||
{
|
{
|
||||||
public required string Id { get; set; } = Guid.NewGuid().ToString();
|
public required string Id { get; set; } = Guid.NewGuid().ToString();
|
||||||
public required string TourName { get; set; }
|
public required string TourName { get; set; }
|
||||||
public string TourCountry { get; set; }
|
public string? TourCountry { get; set; }
|
||||||
public double Price { get; set; }
|
public double Price { get; set; }
|
||||||
public TourType Type { get; set; }
|
public TourType Type { get; set; }
|
||||||
[ForeignKey("TourId")]
|
[ForeignKey("TourId")]
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace MagicCarpetTests.StoragesContracts;
|
|
||||||
|
|
||||||
class TourStorageContractTests
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -25,7 +25,7 @@ class EmployeeStorageContractTests : BaseStorageContractTest
|
|||||||
[TearDown]
|
[TearDown]
|
||||||
public void TearDown()
|
public void TearDown()
|
||||||
{
|
{
|
||||||
MagicCarpetDbContext.Database.ExecuteSqlRaw("TRUNCATE \"Employees\" CASCADE;");
|
MagicCarpetDbContext.Database.ExecuteSqlRaw("TRUNCATE \"Employees\"CASCADE; ");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -55,7 +55,7 @@ class EmployeeStorageContractTests : BaseStorageContractTest
|
|||||||
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 1", postId);
|
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 1", postId);
|
||||||
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 2", postId);
|
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 2", postId);
|
||||||
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 3");
|
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 3");
|
||||||
var list = _employeeStorageContract.GetList(email: postId);
|
var list = _employeeStorageContract.GetList(postId: postId);
|
||||||
Assert.That(list, Is.Not.Null);
|
Assert.That(list, Is.Not.Null);
|
||||||
Assert.That(list, Has.Count.EqualTo(2));
|
Assert.That(list, Has.Count.EqualTo(2));
|
||||||
Assert.That(list.All(x => x.PostId == postId));
|
Assert.That(list.All(x => x.PostId == postId));
|
||||||
@@ -66,7 +66,7 @@ class EmployeeStorageContractTests : BaseStorageContractTest
|
|||||||
var email = Guid.NewGuid().ToString();
|
var email = Guid.NewGuid().ToString();
|
||||||
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 1", email);
|
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 1", email);
|
||||||
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 2", email);
|
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 2", email);
|
||||||
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 3");
|
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 3", email);
|
||||||
var list = _employeeStorageContract.GetList(email: email);
|
var list = _employeeStorageContract.GetList(email: email);
|
||||||
Assert.That(list, Is.Not.Null);
|
Assert.That(list, Is.Not.Null);
|
||||||
Assert.That(list, Has.Count.EqualTo(2));
|
Assert.That(list, Has.Count.EqualTo(2));
|
||||||
@@ -104,7 +104,7 @@ class EmployeeStorageContractTests : BaseStorageContractTest
|
|||||||
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 1", postId, "email@mail.ru", birthDate: DateTime.UtcNow.AddYears(-25), employmentDate: DateTime.UtcNow.AddDays(-2));
|
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 1", postId, "email@mail.ru", birthDate: DateTime.UtcNow.AddYears(-25), employmentDate: DateTime.UtcNow.AddDays(-2));
|
||||||
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 2", postId, "email@mail.ru", birthDate: DateTime.UtcNow.AddYears(-22), employmentDate: DateTime.UtcNow.AddDays(-1));
|
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 2", postId, "email@mail.ru", birthDate: DateTime.UtcNow.AddYears(-22), employmentDate: DateTime.UtcNow.AddDays(-1));
|
||||||
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 3", postId, "email@mail.ru", birthDate: DateTime.UtcNow.AddYears(-21), employmentDate: DateTime.UtcNow.AddDays(-1));
|
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 3", postId, "email@mail.ru", birthDate: DateTime.UtcNow.AddYears(-21), employmentDate: DateTime.UtcNow.AddDays(-1));
|
||||||
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 4", "email@mail.ru", birthDate: DateTime.UtcNow.AddYears(-20), employmentDate: DateTime.UtcNow.AddDays(1));
|
InsertEmployeeToDatabaseAndReturn(Guid.NewGuid().ToString(), "fio 4", postId, "email@mail.ru", birthDate: DateTime.UtcNow.AddYears(-20), employmentDate: DateTime.UtcNow.AddDays(1));
|
||||||
var list = _employeeStorageContract.GetList(postId: postId, email: "email@mail.ru", fromBirthDate: DateTime.UtcNow.AddYears(-21).AddMinutes(-1), toBirthDate: DateTime.UtcNow.AddYears(-20).AddMinutes(1), fromEmploymentDate: DateTime.UtcNow.AddDays(-1).AddMinutes(-1), toEmploymentDate: DateTime.UtcNow.AddDays(1).AddMinutes(1));
|
var list = _employeeStorageContract.GetList(postId: postId, email: "email@mail.ru", fromBirthDate: DateTime.UtcNow.AddYears(-21).AddMinutes(-1), toBirthDate: DateTime.UtcNow.AddYears(-20).AddMinutes(1), fromEmploymentDate: DateTime.UtcNow.AddDays(-1).AddMinutes(-1), toEmploymentDate: DateTime.UtcNow.AddDays(1).AddMinutes(1));
|
||||||
Assert.That(list, Is.Not.Null);
|
Assert.That(list, Is.Not.Null);
|
||||||
Assert.That(list, Has.Count.EqualTo(1));
|
Assert.That(list, Has.Count.EqualTo(1));
|
||||||
@@ -0,0 +1,251 @@
|
|||||||
|
using MagicCarpetContracts.DataModels;
|
||||||
|
using MagicCarpetContracts.Enums;
|
||||||
|
using MagicCarpetContracts.Exceptions;
|
||||||
|
using MagicCarpetDatabase.Implementations;
|
||||||
|
using MagicCarpetDatabase.Models;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static NUnit.Framework.Internal.OSPlatform;
|
||||||
|
|
||||||
|
namespace MagicCarpetTests.StoragesContracts;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
internal class TourStorageContractTests : BaseStorageContractTest
|
||||||
|
{
|
||||||
|
private TourStorageContract _tourStorageContract;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp()
|
||||||
|
{
|
||||||
|
_tourStorageContract = new TourStorageContract(MagicCarpetDbContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public void TearDown()
|
||||||
|
{
|
||||||
|
MagicCarpetDbContext.Database.ExecuteSqlRaw("TRUNCATE \"Tours\" CASCADE;");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_GetList_WhenHaveRecords_Test()
|
||||||
|
{
|
||||||
|
var tour = InsertTourToDatabaseAndReturn(Guid.NewGuid().ToString(),"name 1");
|
||||||
|
InsertTourToDatabaseAndReturn(Guid.NewGuid().ToString(), "name 2");
|
||||||
|
InsertTourToDatabaseAndReturn(Guid.NewGuid().ToString(), "name 3");
|
||||||
|
var list = _tourStorageContract.GetList();
|
||||||
|
Assert.That(list, Is.Not.Null);
|
||||||
|
Assert.That(list, Has.Count.EqualTo(3));
|
||||||
|
AssertElement(list.First(x => x.Id == tour.Id), tour);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_GetList_WhenNoRecords_Test()
|
||||||
|
{
|
||||||
|
var list = _tourStorageContract.GetList();
|
||||||
|
Assert.That(list, Is.Not.Null);
|
||||||
|
Assert.That(list, Is.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_GetHistoryByTourId_WhenHaveRecords_Test()
|
||||||
|
{
|
||||||
|
var tour = InsertTourToDatabaseAndReturn(Guid.NewGuid().ToString(), "name 1");
|
||||||
|
InsertTourHistoryToDatabaseAndReturn(tour.Id, 20, DateTime.UtcNow.AddDays(-1));
|
||||||
|
InsertTourHistoryToDatabaseAndReturn(tour.Id, 30, DateTime.UtcNow.AddMinutes(-10));
|
||||||
|
InsertTourHistoryToDatabaseAndReturn(tour.Id, 40, DateTime.UtcNow.AddDays(1));
|
||||||
|
var list = _tourStorageContract.GetHistoryByTourId(tour.Id);
|
||||||
|
Assert.That(list, Is.Not.Null);
|
||||||
|
Assert.That(list, Has.Count.EqualTo(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_GetHistoryByTourId_WhenNoRecords_Test()
|
||||||
|
{
|
||||||
|
var tour = InsertTourToDatabaseAndReturn(Guid.NewGuid().ToString(), "name 1");
|
||||||
|
InsertTourHistoryToDatabaseAndReturn(tour.Id, 20, DateTime.UtcNow.AddDays(-1));
|
||||||
|
InsertTourHistoryToDatabaseAndReturn(tour.Id, 30, DateTime.UtcNow.AddMinutes(-10));
|
||||||
|
InsertTourHistoryToDatabaseAndReturn(tour.Id, 40, DateTime.UtcNow.AddDays(1));
|
||||||
|
var list = _tourStorageContract.GetHistoryByTourId(Guid.NewGuid().ToString());
|
||||||
|
Assert.That(list, Is.Not.Null);
|
||||||
|
Assert.That(list, Has.Count.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_GetElementById_WhenHaveRecord_Test()
|
||||||
|
{
|
||||||
|
var tour = InsertTourToDatabaseAndReturn(Guid.NewGuid().ToString(), "name1");
|
||||||
|
AssertElement(_tourStorageContract.GetElementById(tour.Id), tour);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_GetElementById_WhenNoRecord_Test()
|
||||||
|
{
|
||||||
|
InsertTourToDatabaseAndReturn(Guid.NewGuid().ToString(), "name1");
|
||||||
|
Assert.That(() => _tourStorageContract.GetElementById(Guid.NewGuid().ToString()), Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_GetElementByName_WhenHaveRecord_Test()
|
||||||
|
{
|
||||||
|
var tour = InsertTourToDatabaseAndReturn(Guid.NewGuid().ToString(), "name1");
|
||||||
|
AssertElement(_tourStorageContract.GetElementByName(tour.TourName), tour);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_GetElementByName_WhenNoRecord_Test()
|
||||||
|
{
|
||||||
|
InsertTourToDatabaseAndReturn(Guid.NewGuid().ToString(), "name1");
|
||||||
|
Assert.That(() => _tourStorageContract.GetElementByName("name"), Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_AddElement_WhenIsDeletedIsTrue_Test()
|
||||||
|
{
|
||||||
|
var tour = CreateModel(Guid.NewGuid().ToString(), "name");
|
||||||
|
Assert.That(() => _tourStorageContract.AddElement(tour), Throws.Nothing);
|
||||||
|
AssertElement(GetTourFromDatabaseById(tour.Id), CreateModel(tour.Id, _manufacturer.Id, isDeleted: false));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_AddElement_WhenHaveRecordWithSameId_Test()
|
||||||
|
{
|
||||||
|
var tour = CreateModel(Guid.NewGuid().ToString(), _manufacturer.Id);
|
||||||
|
InsertTourToDatabaseAndReturn(tour.Id, "name1", tourName: "name unique");
|
||||||
|
Assert.That(() => _tourStorageContract.AddElement(tour), Throws.TypeOf<ElementExistsException>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_AddElement_WhenHaveRecordWithSameName_Test()
|
||||||
|
{
|
||||||
|
var tour = CreateModel(Guid.NewGuid().ToString(), _manufacturer.Id, "name unique", isDeleted: false);
|
||||||
|
InsertTourToDatabaseAndReturn(Guid.NewGuid().ToString(), _manufacturer.Id, tourName: tour.TourName, isDeleted: false);
|
||||||
|
Assert.That(() => _tourStorageContract.AddElement(tour), Throws.TypeOf<ElementExistsException>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_AddElement_WhenHaveRecordWithSameNameButOneWasDeleted_Test()
|
||||||
|
{
|
||||||
|
var tour = CreateModel(Guid.NewGuid().ToString(), _manufacturer.Id, "name unique", isDeleted: false);
|
||||||
|
InsertTourToDatabaseAndReturn(Guid.NewGuid().ToString(), _manufacturer.Id, tourName: tour.TourName, isDeleted: true);
|
||||||
|
Assert.That(() => _tourStorageContract.AddElement(tour), Throws.Nothing);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_UpdElement_Test()
|
||||||
|
{
|
||||||
|
var tour = CreateModel(Guid.NewGuid().ToString(), _manufacturer.Id, isDeleted: false);
|
||||||
|
InsertTourToDatabaseAndReturn(tour.Id, _manufacturer.Id, isDeleted: false);
|
||||||
|
_tourStorageContract.UpdElement(tour);
|
||||||
|
AssertElement(GetTourFromDatabaseById(tour.Id), tour);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_UpdElement_WhenIsDeletedIsTrue_Test()
|
||||||
|
{
|
||||||
|
var tour = CreateModel(Guid.NewGuid().ToString(), _manufacturer.Id, isDeleted: true);
|
||||||
|
InsertTourToDatabaseAndReturn(tour.Id, _manufacturer.Id, isDeleted: false);
|
||||||
|
_tourStorageContract.UpdElement(tour);
|
||||||
|
AssertElement(GetTourFromDatabaseById(tour.Id), CreateModel(tour.Id, _manufacturer.Id, isDeleted: false));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_UpdElement_WhenNoRecordWithThisId_Test()
|
||||||
|
{
|
||||||
|
Assert.That(() => _tourStorageContract.UpdElement(CreateModel(Guid.NewGuid().ToString(), _manufacturer.Id)), Throws.TypeOf<ElementNotFoundException>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_UpdElement_WhenHaveRecordWithSameName_Test()
|
||||||
|
{
|
||||||
|
var tour = CreateModel(Guid.NewGuid().ToString(), _manufacturer.Id, "name unique", isDeleted: false);
|
||||||
|
InsertTourToDatabaseAndReturn(tour.Id, _manufacturer.Id, tourName: "name");
|
||||||
|
InsertTourToDatabaseAndReturn(Guid.NewGuid().ToString(), _manufacturer.Id, tourName: tour.TourName);
|
||||||
|
Assert.That(() => _tourStorageContract.UpdElement(tour), Throws.TypeOf<ElementExistsException>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_UpdElement_WhenHaveRecordWithSameNameButOneWasDeleted_Test()
|
||||||
|
{
|
||||||
|
var tour = CreateModel(Guid.NewGuid().ToString(), _manufacturer.Id, "name unique", isDeleted: false);
|
||||||
|
InsertTourToDatabaseAndReturn(tour.Id, _manufacturer.Id, tourName: "name");
|
||||||
|
InsertTourToDatabaseAndReturn(Guid.NewGuid().ToString(), _manufacturer.Id, tourName: tour.TourName, isDeleted: true);
|
||||||
|
Assert.That(() => _tourStorageContract.UpdElement(tour), Throws.Nothing);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_UpdElement_WhenRecordWasDeleted_Test()
|
||||||
|
{
|
||||||
|
var tour = CreateModel(Guid.NewGuid().ToString(), "name1");
|
||||||
|
InsertTourToDatabaseAndReturn(tour.Id);
|
||||||
|
Assert.That(() => _tourStorageContract.UpdElement(tour), Throws.TypeOf<ElementNotFoundException>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_DelElement_Test()
|
||||||
|
{
|
||||||
|
var tour = InsertTourToDatabaseAndReturn(Guid.NewGuid().ToString());
|
||||||
|
_tourStorageContract.DelElement(tour.Id);
|
||||||
|
var element = GetTourFromDatabaseById(tour.Id);
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(element, Is.Not.Null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Try_DelElement_WhenNoRecordWithThisId_Test()
|
||||||
|
{
|
||||||
|
Assert.That(() => _tourStorageContract.DelElement(Guid.NewGuid().ToString()), Throws.TypeOf<ElementNotFoundException>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Tour InsertTourToDatabaseAndReturn(string id, string tourName = "test", string tourCountry = "country", double price = 1, TourType tourType = TourType.Sightseeing)
|
||||||
|
{
|
||||||
|
var tour = new Tour() { Id = id, TourName = tourName, TourCountry = tourCountry, Price = price, Type = tourType, };
|
||||||
|
MagicCarpetDbContext.Tours.Add(tour);
|
||||||
|
MagicCarpetDbContext.SaveChanges();
|
||||||
|
return tour;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TourHistory InsertTourHistoryToDatabaseAndReturn(string tourId, double price, DateTime changeDate)
|
||||||
|
{
|
||||||
|
var tourHistory = new TourHistory() { Id = Guid.NewGuid().ToString(), TourId = tourId, OldPrice = price, ChangeDate = changeDate };
|
||||||
|
MagicCarpetDbContext.TourHistories.Add(tourHistory);
|
||||||
|
MagicCarpetDbContext.SaveChanges();
|
||||||
|
return tourHistory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AssertElement(TourDataModel? actual, Tour expected)
|
||||||
|
{
|
||||||
|
Assert.That(actual, Is.Not.Null);
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(actual.Id, Is.EqualTo(expected.Id));
|
||||||
|
Assert.That(actual.TourName, Is.EqualTo(expected.TourName));
|
||||||
|
Assert.That(actual.TourCountry, Is.EqualTo(expected.TourCountry));
|
||||||
|
Assert.That(actual.Price, Is.EqualTo(expected.Price));
|
||||||
|
Assert.That(actual.Type, Is.EqualTo(expected.Type));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TourDataModel CreateModel(string id, string manufacturerId, string tourName = "test", string tourCountry = "country", double price = 1, TourType tourType = TourType.Sightseeing)
|
||||||
|
=> new(id, tourName, tourCountry, price, tourType);
|
||||||
|
|
||||||
|
private Tour? GetTourFromDatabaseById(string id) => MagicCarpetDbContext.Tours.FirstOrDefault(x => x.Id == id);
|
||||||
|
|
||||||
|
private static void AssertElement(Tour? actual, TourDataModel expected)
|
||||||
|
{
|
||||||
|
Assert.That(actual, Is.Not.Null);
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(actual.Id, Is.EqualTo(expected.Id));
|
||||||
|
Assert.That(actual.TourName, Is.EqualTo(expected.TourName));
|
||||||
|
Assert.That(actual.TourCountry, Is.EqualTo(expected.TourCountry));
|
||||||
|
Assert.That(actual.Price, Is.EqualTo(expected.Price));
|
||||||
|
Assert.That(actual.Type, Is.EqualTo(expected.Type));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user