Метод добавления changeLog
This commit is contained in:
parent
44730bb66e
commit
c5645df2e6
@ -21,11 +21,11 @@ public class ChangeLogController : ControllerBase, IChangeLogApi
|
|||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<ActionResult<int>> Add(
|
public async Task<ActionResult<int>> Add(
|
||||||
[FromRoute] Guid idDiscriminator,
|
[FromRoute] Guid idDiscriminator,
|
||||||
[FromBody]IDictionary<string, object> dtos,
|
ChangeLogDto dto,
|
||||||
CancellationToken token)
|
CancellationToken token)
|
||||||
{
|
{
|
||||||
var userId = User.GetUserId<Guid>();
|
var userId = User.GetUserId<Guid>();
|
||||||
var result = await repository.InsertRange(userId, idDiscriminator, [dtos], token);
|
var result = await repository.InsertRange(userId, idDiscriminator, [dto], token);
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
@ -54,7 +54,8 @@ public class ChangeLogController : ControllerBase, IChangeLogApi
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ActionResult<IEnumerable<ChangeLogDto<IDictionary<string, object>>>>> GetChangeLogForDate(DateTimeOffset historyMoment, CancellationToken token)
|
[HttpGet("history")]
|
||||||
|
public Task<ActionResult<IEnumerable<ChangeLogDto>>> GetChangeLogForDate(DateTimeOffset historyMoment, CancellationToken token)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Npgsql;
|
||||||
|
|
||||||
namespace Persistence.Database.Model;
|
namespace Persistence.Database.Model;
|
||||||
|
|
||||||
@ -11,7 +12,11 @@ public static class DependencyInjection
|
|||||||
string connectionStringName = "DefaultConnection";
|
string connectionStringName = "DefaultConnection";
|
||||||
|
|
||||||
services.AddDbContext<PersistenceDbContext>(options =>
|
services.AddDbContext<PersistenceDbContext>(options =>
|
||||||
options.UseNpgsql(configuration.GetConnectionString(connectionStringName)));
|
{
|
||||||
|
var dataSourceBuilder = new NpgsqlDataSourceBuilder(configuration.GetConnectionString(connectionStringName));
|
||||||
|
dataSourceBuilder.EnableDynamicJson();
|
||||||
|
options.UseNpgsql(dataSourceBuilder.Build());
|
||||||
|
});
|
||||||
|
|
||||||
services.AddScoped<DbContext>(provider => provider.GetRequiredService<PersistenceDbContext>());
|
services.AddScoped<DbContext>(provider => provider.GetRequiredService<PersistenceDbContext>());
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
// <auto-generated />
|
// <auto-generated />
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
@ -12,8 +13,8 @@ using Persistence.Database.Model;
|
|||||||
namespace Persistence.Database.Postgres.Migrations
|
namespace Persistence.Database.Postgres.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(PersistenceDbContext))]
|
[DbContext(typeof(PersistenceDbContext))]
|
||||||
[Migration("20241122124437_AddChangeLog")]
|
[Migration("20241126071115_Add_ChangeLog")]
|
||||||
partial class AddChangeLog
|
partial class Add_ChangeLog
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
@ -38,23 +39,39 @@ namespace Persistence.Database.Postgres.Migrations
|
|||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("Creation");
|
.HasColumnName("Creation");
|
||||||
|
|
||||||
b.Property<int>("IdAuthor")
|
b.Property<double>("DepthEnd")
|
||||||
.HasColumnType("integer")
|
.HasColumnType("double precision")
|
||||||
|
.HasColumnName("DepthEnd");
|
||||||
|
|
||||||
|
b.Property<double>("DepthStart")
|
||||||
|
.HasColumnType("double precision")
|
||||||
|
.HasColumnName("DepthStart");
|
||||||
|
|
||||||
|
b.Property<Guid>("IdAuthor")
|
||||||
|
.HasColumnType("uuid")
|
||||||
.HasColumnName("IdAuthor");
|
.HasColumnName("IdAuthor");
|
||||||
|
|
||||||
b.Property<int?>("IdEditor")
|
b.Property<Guid>("IdDiscriminator")
|
||||||
.HasColumnType("integer")
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("IdDiscriminator");
|
||||||
|
|
||||||
|
b.Property<Guid?>("IdEditor")
|
||||||
|
.HasColumnType("uuid")
|
||||||
.HasColumnName("IdEditor");
|
.HasColumnName("IdEditor");
|
||||||
|
|
||||||
b.Property<int?>("IdNext")
|
b.Property<Guid?>("IdNext")
|
||||||
.HasColumnType("integer")
|
.HasColumnType("uuid")
|
||||||
.HasColumnName("IdNext");
|
.HasColumnName("IdNext");
|
||||||
|
|
||||||
|
b.Property<Guid>("IdSection")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("IdSection");
|
||||||
|
|
||||||
b.Property<DateTimeOffset?>("Obsolete")
|
b.Property<DateTimeOffset?>("Obsolete")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("Obsolete");
|
.HasColumnName("Obsolete");
|
||||||
|
|
||||||
b.Property<object>("Value")
|
b.Property<IDictionary<string, object>>("Value")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("jsonb")
|
.HasColumnType("jsonb")
|
||||||
.HasColumnName("Value");
|
.HasColumnName("Value");
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
@ -6,7 +7,7 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
|||||||
namespace Persistence.Database.Postgres.Migrations
|
namespace Persistence.Database.Postgres.Migrations
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class AddChangeLog : Migration
|
public partial class Add_ChangeLog : Migration
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
@ -16,12 +17,16 @@ namespace Persistence.Database.Postgres.Migrations
|
|||||||
columns: table => new
|
columns: table => new
|
||||||
{
|
{
|
||||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
IdAuthor = table.Column<int>(type: "integer", nullable: false),
|
IdDiscriminator = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
IdEditor = table.Column<int>(type: "integer", nullable: true),
|
IdAuthor = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
IdEditor = table.Column<Guid>(type: "uuid", nullable: true),
|
||||||
Creation = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
Creation = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||||
Obsolete = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
Obsolete = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
IdNext = table.Column<int>(type: "integer", nullable: true),
|
IdNext = table.Column<Guid>(type: "uuid", nullable: true),
|
||||||
Value = table.Column<object>(type: "jsonb", nullable: false)
|
DepthStart = table.Column<double>(type: "double precision", nullable: false),
|
||||||
|
DepthEnd = table.Column<double>(type: "double precision", nullable: false),
|
||||||
|
IdSection = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Value = table.Column<IDictionary<string, object>>(type: "jsonb", nullable: false)
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
@ -1,5 +1,6 @@
|
|||||||
// <auto-generated />
|
// <auto-generated />
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
@ -35,23 +36,39 @@ namespace Persistence.Database.Postgres.Migrations
|
|||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("Creation");
|
.HasColumnName("Creation");
|
||||||
|
|
||||||
b.Property<int>("IdAuthor")
|
b.Property<double>("DepthEnd")
|
||||||
.HasColumnType("integer")
|
.HasColumnType("double precision")
|
||||||
|
.HasColumnName("DepthEnd");
|
||||||
|
|
||||||
|
b.Property<double>("DepthStart")
|
||||||
|
.HasColumnType("double precision")
|
||||||
|
.HasColumnName("DepthStart");
|
||||||
|
|
||||||
|
b.Property<Guid>("IdAuthor")
|
||||||
|
.HasColumnType("uuid")
|
||||||
.HasColumnName("IdAuthor");
|
.HasColumnName("IdAuthor");
|
||||||
|
|
||||||
b.Property<int?>("IdEditor")
|
b.Property<Guid>("IdDiscriminator")
|
||||||
.HasColumnType("integer")
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("IdDiscriminator");
|
||||||
|
|
||||||
|
b.Property<Guid?>("IdEditor")
|
||||||
|
.HasColumnType("uuid")
|
||||||
.HasColumnName("IdEditor");
|
.HasColumnName("IdEditor");
|
||||||
|
|
||||||
b.Property<int?>("IdNext")
|
b.Property<Guid?>("IdNext")
|
||||||
.HasColumnType("integer")
|
.HasColumnType("uuid")
|
||||||
.HasColumnName("IdNext");
|
.HasColumnName("IdNext");
|
||||||
|
|
||||||
|
b.Property<Guid>("IdSection")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("IdSection");
|
||||||
|
|
||||||
b.Property<DateTimeOffset?>("Obsolete")
|
b.Property<DateTimeOffset?>("Obsolete")
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp with time zone")
|
||||||
.HasColumnName("Obsolete");
|
.HasColumnName("Obsolete");
|
||||||
|
|
||||||
b.Property<object>("Value")
|
b.Property<IDictionary<string, object>>("Value")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("jsonb")
|
.HasColumnType("jsonb")
|
||||||
.HasColumnName("Value");
|
.HasColumnName("Value");
|
||||||
|
@ -3,3 +3,9 @@
|
|||||||
dotnet ef migrations add <MigrationName> --project Persistence.Database.Postgres
|
dotnet ef migrations add <MigrationName> --project Persistence.Database.Postgres
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Откатить миграцию
|
||||||
|
```
|
||||||
|
dotnet ef migrations remove --project Persistence.Database.Postgres
|
||||||
|
```
|
||||||
|
Удаляется последняя созданная миграция.
|
@ -51,6 +51,24 @@ public class ChangeLog : IChangeLog
|
|||||||
[Column("IdNext")]
|
[Column("IdNext")]
|
||||||
public Guid? IdNext { get; set; }
|
public Guid? IdNext { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Глубина забоя на дату начала интервала
|
||||||
|
/// </summary>
|
||||||
|
[Column("DepthStart")]
|
||||||
|
public double DepthStart { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Глубина забоя на дату окончания интервала
|
||||||
|
/// </summary>
|
||||||
|
[Column("DepthEnd")]
|
||||||
|
public double DepthEnd { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ключ секции
|
||||||
|
/// </summary>
|
||||||
|
[Column("IdSection")]
|
||||||
|
public Guid IdSection { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Значение
|
/// Значение
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
|
|
||||||
namespace Persistence.Database.Model;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Часть записи, описывающая изменение данных, содержащие начальную и конечную глубину, а также секцию
|
|
||||||
/// </summary>
|
|
||||||
public class ChangeLogWithWellDepthAndSectionId : ChangeLog
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Глубина забоя на дату начала интервала
|
|
||||||
/// </summary>
|
|
||||||
[Column("DepthStart")]
|
|
||||||
public double? DepthStart { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Глубина забоя на дату окончания интервала
|
|
||||||
/// </summary>
|
|
||||||
[Column("DepthEnd")]
|
|
||||||
public double? DepthEnd { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ключ секции
|
|
||||||
/// </summary>
|
|
||||||
[Column("IdSection")]
|
|
||||||
public Guid IdSection { get; set; }
|
|
||||||
}
|
|
@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations.Schema;
|
|||||||
namespace Persistence.Database.Model;
|
namespace Persistence.Database.Model;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Часть записи описывающая изменение
|
/// Часть записи, описывающая изменение
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IChangeLog
|
public interface IChangeLog
|
||||||
{
|
{
|
||||||
|
@ -24,7 +24,7 @@ public class ChangeLogRepository : IChangeLogRepository
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<IEnumerable<ChangeLogDto<IDictionary<string, object>>>> GetChangeLogForDate(DateTimeOffset? updateFrom, CancellationToken token)
|
public Task<IEnumerable<ChangeLogDto>> GetChangeLogForDate(DateTimeOffset? updateFrom, CancellationToken token)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
@ -44,7 +44,7 @@ public class ChangeLogRepository : IChangeLogRepository
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<int> InsertRange(Guid idUser, Guid idDiscriminator, IEnumerable<IDictionary<string, object>> dtos, CancellationToken token)
|
public Task<int> InsertRange(Guid idUser, Guid idDiscriminator, IEnumerable<ChangeLogDto> dtos, CancellationToken token)
|
||||||
{
|
{
|
||||||
var entities = new List<ChangeLog>();
|
var entities = new List<ChangeLog>();
|
||||||
foreach (var dto in dtos)
|
foreach (var dto in dtos)
|
||||||
@ -54,8 +54,11 @@ public class ChangeLogRepository : IChangeLogRepository
|
|||||||
IdAuthor = idUser,
|
IdAuthor = idUser,
|
||||||
IdDiscriminator = idDiscriminator,
|
IdDiscriminator = idDiscriminator,
|
||||||
IdEditor = idUser,
|
IdEditor = idUser,
|
||||||
Value = dto,
|
Value = dto.Value,
|
||||||
Creation = DateTimeOffset.UtcNow
|
Creation = DateTimeOffset.UtcNow,
|
||||||
|
IdSection = dto.IdSection,
|
||||||
|
DepthStart = dto.DepthStart,
|
||||||
|
DepthEnd = dto.DepthEnd,
|
||||||
};
|
};
|
||||||
entity.Id = idUser;
|
entity.Id = idUser;
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ public interface IChangeLogApi
|
|||||||
/// <param name="historyMoment"></param>
|
/// <param name="historyMoment"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<ActionResult<IEnumerable<ChangeLogDto<IDictionary<string, object>>>>> GetChangeLogForDate(DateTimeOffset historyMoment, CancellationToken token);
|
Task<ActionResult<IEnumerable<ChangeLogDto>>> GetChangeLogForDate(DateTimeOffset historyMoment, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Добавить одну запись
|
/// Добавить одну запись
|
||||||
@ -29,7 +29,7 @@ public interface IChangeLogApi
|
|||||||
/// <param name="dto"></param>
|
/// <param name="dto"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<ActionResult<int>> Add(Guid idDiscriminator, IDictionary<string, object> dto, CancellationToken token);
|
Task<ActionResult<int>> Add(Guid idDiscriminator, ChangeLogDto dto, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Добавить несколько записей
|
/// Добавить несколько записей
|
||||||
|
@ -1,20 +1,14 @@
|
|||||||
|
|
||||||
namespace Persistence.Models;
|
namespace Persistence.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Часть записи описывающая изменение
|
/// Часть записи описывающая изменение
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ChangeLogDto<T> : IChangeLogDto
|
public class ChangeLogDto
|
||||||
where T: IDictionary<string, object>
|
|
||||||
{
|
{
|
||||||
public ChangeLogDto()
|
public ChangeLogDto()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
/// <summary>
|
|
||||||
/// Запись
|
|
||||||
/// </summary>
|
|
||||||
public required T Item { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@ -46,8 +40,23 @@ public class ChangeLogDto<T> : IChangeLogDto
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid? IdNext { get; set; }
|
public Guid? IdNext { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Глубина забоя на дату начала интервала
|
||||||
|
/// </summary>
|
||||||
|
public double DepthStart { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Глубина забоя на дату окончания интервала
|
||||||
|
/// </summary>
|
||||||
|
public double DepthEnd { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ключ секции
|
||||||
|
/// </summary>
|
||||||
|
public Guid IdSection { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Объект записи
|
/// Объект записи
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public required object Value { get; set; }
|
public required IDictionary<string, object> Value { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ public interface IChangeLogRepository //: ISyncRepository<TDto>
|
|||||||
/// <param name="dtos"></param>
|
/// <param name="dtos"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<int> InsertRange(Guid idUser, Guid idDiscriminator, IEnumerable<IDictionary<string, object>> dtos, CancellationToken token);
|
Task<int> InsertRange(Guid idUser, Guid idDiscriminator, IEnumerable<ChangeLogDto> dtos, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Редактирование записей
|
/// Редактирование записей
|
||||||
@ -76,7 +76,7 @@ public interface IChangeLogRepository //: ISyncRepository<TDto>
|
|||||||
/// <param name="updateFrom"></param>
|
/// <param name="updateFrom"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IEnumerable<ChangeLogDto<IDictionary<string, object>>>> GetChangeLogForDate(DateTimeOffset? updateFrom, CancellationToken token);
|
Task<IEnumerable<ChangeLogDto>> GetChangeLogForDate(DateTimeOffset? updateFrom, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение текущих сейчас записей по параметрам
|
/// Получение текущих сейчас записей по параметрам
|
||||||
|
Loading…
Reference in New Issue
Block a user