Диман сделай пж SupplyDoc
This commit is contained in:
parent
a42202f627
commit
b2b2922acf
@ -1,4 +1,11 @@
|
|||||||
using System;
|
using Contracts.BindingModels;
|
||||||
|
using Contracts.Converters;
|
||||||
|
using Contracts.SearchModels;
|
||||||
|
using Contracts.StorageContracts;
|
||||||
|
using Contracts.ViewModels;
|
||||||
|
using DatabaseImplement.Models;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -6,7 +13,65 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace BusinessLogic.BusinessLogic
|
namespace BusinessLogic.BusinessLogic
|
||||||
{
|
{
|
||||||
internal class SellLogic
|
public class SellLogic
|
||||||
{
|
{
|
||||||
|
private readonly ISellStorage _sellStorage;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
|
public SellLogic(ISellStorage sellStorage, ILogger logger)
|
||||||
|
{
|
||||||
|
_sellStorage = sellStorage;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
public SellViewModel Create(SellBindingModel model)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(model);
|
||||||
|
var sell = _sellStorage.Insert(model);
|
||||||
|
if (sell is null)
|
||||||
|
{
|
||||||
|
throw new Exception("Insert operation failed.");
|
||||||
|
}
|
||||||
|
return sell;
|
||||||
|
}
|
||||||
|
public SellViewModel GetElement(SellSearchModel model)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(model);
|
||||||
|
var sell = _sellStorage.GetElement(model);
|
||||||
|
if (sell is null)
|
||||||
|
{
|
||||||
|
throw new Exception("Get element operation failed.");
|
||||||
|
}
|
||||||
|
return sell;
|
||||||
|
}
|
||||||
|
public IEnumerable<SellViewModel> GetElements(SellSearchModel? model)
|
||||||
|
{
|
||||||
|
var sell_list = _sellStorage.GetList(model);
|
||||||
|
if (sell_list is null || sell_list.Count() == 0)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("ReadList return null list");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return sell_list;
|
||||||
|
}
|
||||||
|
public SellViewModel Update(SellSearchModel model)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(model);
|
||||||
|
var sell = _sellStorage.GetElement(model);
|
||||||
|
if (sell is null)
|
||||||
|
{
|
||||||
|
throw new Exception("Update operation failed.");
|
||||||
|
}
|
||||||
|
return sell;
|
||||||
|
}
|
||||||
|
public SellViewModel Delete(SellSearchModel model)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(model);
|
||||||
|
var sell = _sellStorage.Delete(model);
|
||||||
|
if (sell is null)
|
||||||
|
{
|
||||||
|
throw new Exception("Update operation failed.");
|
||||||
|
}
|
||||||
|
return sell;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,5 +10,6 @@ namespace Contracts.BindingModels
|
|||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public DateTime DateSell { get; set; }
|
public DateTime DateSell { get; set; }
|
||||||
|
public Guid? SupplyDocId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
using System;
|
using Contracts.BindingModels;
|
||||||
|
using Contracts.ViewModels;
|
||||||
|
using DataModels.Models;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -8,6 +11,18 @@ namespace Contracts.Converters
|
|||||||
{
|
{
|
||||||
public class SellConverter
|
public class SellConverter
|
||||||
{
|
{
|
||||||
|
public static SellViewModel ToView(SellBindingModel model) => new()
|
||||||
|
{
|
||||||
|
Id = model.Id,
|
||||||
|
DateSell = model.DateSell,
|
||||||
|
SupplyDocId = model.SupplyDocId
|
||||||
|
};
|
||||||
|
|
||||||
|
public static SellBindingModel ToBinding(SellViewModel model) => new()
|
||||||
|
{
|
||||||
|
Id = model.Id,
|
||||||
|
DateSell = model.DateSell,
|
||||||
|
SupplyDocId = model.SupplyDocId
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Contracts.BindingModels;
|
using Contracts.BindingModels;
|
||||||
using Contracts.SearchModels;
|
using Contracts.SearchModels;
|
||||||
|
using Contracts.ViewModels;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -10,14 +11,15 @@ namespace Contracts.StorageContracts
|
|||||||
{
|
{
|
||||||
public interface ISellStorage
|
public interface ISellStorage
|
||||||
{
|
{
|
||||||
SellBindingModel? Insert(SellBindingModel model);
|
SellViewModel? Insert(SellBindingModel model);
|
||||||
|
|
||||||
IEnumerable<SellBindingModel> GetList(SellSearchModel? model);
|
IEnumerable<SellViewModel> GetFullList(SellSearchModel? model);
|
||||||
|
IEnumerable<SellViewModel> GetFilteredList(SellSearchModel? model);
|
||||||
|
|
||||||
SellBindingModel? GetElement(SellSearchModel model);
|
SellViewModel? GetElement(SellSearchModel model);
|
||||||
|
|
||||||
SellBindingModel? Update(SellBindingModel model);
|
SellViewModel? Update(SellBindingModel model);
|
||||||
|
|
||||||
SellBindingModel? Delete(SellSearchModel model);
|
SellViewModel? Delete(SellSearchModel model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,6 @@ namespace Contracts.ViewModels
|
|||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public DateTime DateSell { get; set; }
|
public DateTime DateSell { get; set; }
|
||||||
public ISupplyDoc? SupplyDoc { get; set; }
|
public Guid? SupplyDocId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,5 +30,6 @@ namespace DatabaseImplement
|
|||||||
public virtual DbSet<SupplierProduct> SupplierProducts { get; set; } = null!;
|
public virtual DbSet<SupplierProduct> SupplierProducts { get; set; } = null!;
|
||||||
public virtual DbSet<MediaFile> MediaFiles { get; set; } = null!;
|
public virtual DbSet<MediaFile> MediaFiles { get; set; } = null!;
|
||||||
public virtual DbSet<PurchaseProducts> PurchaseProducts { get; set; } = null!;
|
public virtual DbSet<PurchaseProducts> PurchaseProducts { get; set; } = null!;
|
||||||
|
public virtual DbSet<SupplyDoc> SupplyDocs { get; set; } = null!;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,10 @@
|
|||||||
using Contracts.BindingModels;
|
using Contracts.BindingModels;
|
||||||
|
using Contracts.Converters;
|
||||||
using Contracts.SearchModels;
|
using Contracts.SearchModels;
|
||||||
using Contracts.StorageContracts;
|
using Contracts.StorageContracts;
|
||||||
|
using Contracts.ViewModels;
|
||||||
|
using DatabaseImplement.Models;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -11,29 +15,65 @@ namespace DatabaseImplement.Implements
|
|||||||
{
|
{
|
||||||
public class SellStorage : ISellStorage
|
public class SellStorage : ISellStorage
|
||||||
{
|
{
|
||||||
public SellBindingModel? Delete(SellSearchModel model)
|
public SellViewModel? Delete(SellSearchModel model)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SellBindingModel? GetElement(SellSearchModel model)
|
public SellViewModel? GetElement(SellSearchModel model)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<SellBindingModel> GetList(SellSearchModel? model)
|
public IEnumerable<SellViewModel> GetFilteredList(SellSearchModel? model)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SellBindingModel? Insert(SellBindingModel model)
|
public IEnumerable<SellViewModel> GetFullList(SellSearchModel? model)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
using var context = new Database();
|
||||||
|
return context.Sells
|
||||||
|
.Include(x => x.SupplyDoc)
|
||||||
|
.ToList()
|
||||||
|
.Select((Sell sell, int index) => sell.GetViewModel())
|
||||||
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SellBindingModel? Update(SellBindingModel model)
|
public SellViewModel? Insert(SellBindingModel model)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
using var context = new Database();
|
||||||
|
var sell = Sell.Create(context, model);
|
||||||
|
if (sell == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
context.Sells.Add(sell);
|
||||||
|
context.SaveChanges();
|
||||||
|
return sell.GetViewModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SellViewModel? Update(SellBindingModel model)
|
||||||
|
{
|
||||||
|
using var context = new Database();
|
||||||
|
using var transaction = context.Database.BeginTransaction();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sell = context.Sells.FirstOrDefault(rec => rec.Id == model.Id);
|
||||||
|
if (sell == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
sell.Update(model);
|
||||||
|
context.SaveChanges();
|
||||||
|
transaction.Commit();
|
||||||
|
return sell.GetViewModel();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
transaction.Rollback();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ namespace DatabaseImplement.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("MediaFiles");
|
b.ToTable("MediaFiles", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DatabaseImplement.Models.Product", b =>
|
modelBuilder.Entity("DatabaseImplement.Models.Product", b =>
|
||||||
@ -68,7 +68,7 @@ namespace DatabaseImplement.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("Products");
|
b.ToTable("Products", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DatabaseImplement.Models.Purchase", b =>
|
modelBuilder.Entity("DatabaseImplement.Models.Purchase", b =>
|
||||||
@ -90,7 +90,7 @@ namespace DatabaseImplement.Migrations
|
|||||||
|
|
||||||
b.HasIndex("UserId");
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
b.ToTable("Purchases");
|
b.ToTable("Purchases", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DatabaseImplement.Models.PurchaseProducts", b =>
|
modelBuilder.Entity("DatabaseImplement.Models.PurchaseProducts", b =>
|
||||||
@ -114,7 +114,7 @@ namespace DatabaseImplement.Migrations
|
|||||||
|
|
||||||
b.HasIndex("PurchaseId");
|
b.HasIndex("PurchaseId");
|
||||||
|
|
||||||
b.ToTable("PurchaseProducts");
|
b.ToTable("PurchaseProducts", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DatabaseImplement.Models.Role", b =>
|
modelBuilder.Entity("DatabaseImplement.Models.Role", b =>
|
||||||
@ -129,7 +129,7 @@ namespace DatabaseImplement.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("Roles");
|
b.ToTable("Roles", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DatabaseImplement.Models.Sell", b =>
|
modelBuilder.Entity("DatabaseImplement.Models.Sell", b =>
|
||||||
@ -143,7 +143,7 @@ namespace DatabaseImplement.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("Sells");
|
b.ToTable("Sells", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DatabaseImplement.Models.Supplier", b =>
|
modelBuilder.Entity("DatabaseImplement.Models.Supplier", b =>
|
||||||
@ -161,7 +161,7 @@ namespace DatabaseImplement.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("Suppliers");
|
b.ToTable("Suppliers", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DatabaseImplement.Models.SupplierProduct", b =>
|
modelBuilder.Entity("DatabaseImplement.Models.SupplierProduct", b =>
|
||||||
@ -185,7 +185,7 @@ namespace DatabaseImplement.Migrations
|
|||||||
|
|
||||||
b.HasIndex("SupplierId");
|
b.HasIndex("SupplierId");
|
||||||
|
|
||||||
b.ToTable("SupplierProducts");
|
b.ToTable("SupplierProducts", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DatabaseImplement.Models.Supply", b =>
|
modelBuilder.Entity("DatabaseImplement.Models.Supply", b =>
|
||||||
@ -214,7 +214,7 @@ namespace DatabaseImplement.Migrations
|
|||||||
|
|
||||||
b.HasIndex("SupplierId");
|
b.HasIndex("SupplierId");
|
||||||
|
|
||||||
b.ToTable("Supplies");
|
b.ToTable("Supplies", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DatabaseImplement.Models.SupplyProduct", b =>
|
modelBuilder.Entity("DatabaseImplement.Models.SupplyProduct", b =>
|
||||||
@ -238,7 +238,7 @@ namespace DatabaseImplement.Migrations
|
|||||||
|
|
||||||
b.HasIndex("SupplyId");
|
b.HasIndex("SupplyId");
|
||||||
|
|
||||||
b.ToTable("SupplyProducts");
|
b.ToTable("SupplyProducts", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DatabaseImplement.Models.User", b =>
|
modelBuilder.Entity("DatabaseImplement.Models.User", b =>
|
||||||
@ -276,7 +276,7 @@ namespace DatabaseImplement.Migrations
|
|||||||
|
|
||||||
b.HasIndex("RoleId");
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
b.ToTable("Users");
|
b.ToTable("Users", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DatabaseImplement.Models.Purchase", b =>
|
modelBuilder.Entity("DatabaseImplement.Models.Purchase", b =>
|
||||||
|
@ -43,7 +43,7 @@ namespace DatabaseImplement.Models
|
|||||||
Id = model.Id,
|
Id = model.Id,
|
||||||
Name = model.Name,
|
Name = model.Name,
|
||||||
Price = model.Price,
|
Price = model.Price,
|
||||||
Rate = model.Rate,
|
Rate = model.Rating,
|
||||||
IsBeingSold = model.IsBeingSold,
|
IsBeingSold = model.IsBeingSold,
|
||||||
Amount = model.Amount
|
Amount = model.Amount
|
||||||
};
|
};
|
||||||
@ -96,7 +96,7 @@ namespace DatabaseImplement.Models
|
|||||||
Name = Name,
|
Name = Name,
|
||||||
Price = Price,
|
Price = Price,
|
||||||
IsBeingSold = IsBeingSold,
|
IsBeingSold = IsBeingSold,
|
||||||
Rate = Rate,
|
Rating = Rate,
|
||||||
Amount = Amount
|
Amount = Amount
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,16 @@ namespace DatabaseImplement.Models
|
|||||||
}
|
}
|
||||||
[ForeignKey("PurchaseId")]
|
[ForeignKey("PurchaseId")]
|
||||||
public virtual List<PurchaseProducts> Products { get; set; } = new();
|
public virtual List<PurchaseProducts> Products { get; set; } = new();
|
||||||
|
public static Purchase Create(Database context, SellBindingModel model)
|
||||||
|
{
|
||||||
|
return new Purchase()
|
||||||
|
{
|
||||||
|
DatePurchase = DateTime.Now,
|
||||||
|
UserId = Guid.NewGuid(),
|
||||||
|
Status = PurchaseStatus.Unknown,
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
public PurchaseBindingModel GetBindingModel() => new()
|
public PurchaseBindingModel GetBindingModel() => new()
|
||||||
{
|
{
|
||||||
Id = Id,
|
Id = Id,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Contracts.BindingModels;
|
using Contracts.BindingModels;
|
||||||
|
using Contracts.Converters;
|
||||||
using Contracts.ViewModels;
|
using Contracts.ViewModels;
|
||||||
using DataModels.Models;
|
using DataModels.Models;
|
||||||
using System;
|
using System;
|
||||||
@ -13,11 +14,31 @@ namespace DatabaseImplement.Models
|
|||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public DateTime DateSell { get; set; }
|
public DateTime DateSell { get; set; }
|
||||||
|
public Guid? SupplyDocId { get; set; }
|
||||||
|
|
||||||
|
public virtual SupplyDoc? SupplyDoc { get; set; }
|
||||||
|
public static Sell Create(Database context, SellBindingModel model)
|
||||||
|
{
|
||||||
|
return new Sell()
|
||||||
|
{
|
||||||
|
Id = model.Id,
|
||||||
|
DateSell = model.DateSell,
|
||||||
|
SupplyDocId = model.SupplyDocId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public SellBindingModel GetBindingModel() => new()
|
public SellBindingModel GetBindingModel() => new()
|
||||||
{
|
{
|
||||||
Id = Id,
|
Id = Id,
|
||||||
DateSell = DateSell
|
DateSell = DateSell,
|
||||||
|
SupplyDocId = SupplyDocId,
|
||||||
|
};
|
||||||
|
public SellViewModel GetViewModel() => new()
|
||||||
|
{
|
||||||
|
Id = Id,
|
||||||
|
DateSell = DateSell,
|
||||||
|
SupplyDocId = SupplyDocId,
|
||||||
|
|
||||||
};
|
};
|
||||||
public static Sell ToSellFromView(SellViewModel model, Sell sell) => new()
|
public static Sell ToSellFromView(SellViewModel model, Sell sell) => new()
|
||||||
{
|
{
|
||||||
@ -31,14 +52,15 @@ namespace DatabaseImplement.Models
|
|||||||
DateSell = model.DateSell,
|
DateSell = model.DateSell,
|
||||||
};
|
};
|
||||||
|
|
||||||
public void Update(SellBindingModel model, Sell sell)
|
public void Update(SellBindingModel model)
|
||||||
{
|
{
|
||||||
if (model is null)
|
if (model is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("Update user: binding model is null");
|
throw new ArgumentNullException("Update user: binding model is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
DateSell = sell.DateSell;
|
DateSell = model.DateSell;
|
||||||
|
SupplyDocId = model.SupplyDocId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
18
DatabaseImplement/Models/SupplyDoc.cs
Normal file
18
DatabaseImplement/Models/SupplyDoc.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using DataModels.Models;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace DatabaseImplement.Models
|
||||||
|
{
|
||||||
|
public class SupplyDoc : ISupplyDoc
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
[Required]
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public Guid SupplyId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -15,4 +15,11 @@
|
|||||||
<ProjectReference Include="..\Contracts\Contracts.csproj" />
|
<ProjectReference Include="..\Contracts\Contracts.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Update="wwwroot\favicon.ico">
|
||||||
|
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||||
|
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 66 KiB |
Loading…
Reference in New Issue
Block a user