feat : add newsletter and newsletter members , add version 0.8.15.22
add needed controller and models , fix sidebar in responsiverelease
parent
348051c391
commit
75d53a7f76
|
@ -17,7 +17,7 @@
|
||||||
"TaxesFee": 9
|
"TaxesFee": 9
|
||||||
},
|
},
|
||||||
"SiteSettings": {
|
"SiteSettings": {
|
||||||
"BaseUrl": "http://192.168.88.17:32770",
|
"BaseUrl": "http://192.168.88.251:32770",
|
||||||
"KaveNegarApiKey": "3735494B4143727A794346457461576A2B4B6668414973424E333561505A694B",
|
"KaveNegarApiKey": "3735494B4143727A794346457461576A2B4B6668414973424E333561505A694B",
|
||||||
"UserSetting": {
|
"UserSetting": {
|
||||||
"Username": "netinashop",
|
"Username": "netinashop",
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
namespace NetinaShop.Api.Controller;
|
||||||
|
|
||||||
|
public class NewsletterMemberController : ICarterModule
|
||||||
|
{
|
||||||
|
public void AddRoutes(IEndpointRouteBuilder app)
|
||||||
|
{
|
||||||
|
var group = app.NewVersionedApi("Newsletter Members").MapGroup("api/newsletter/member");
|
||||||
|
|
||||||
|
group.MapGet("", GetAllMembersAsync)
|
||||||
|
.WithDisplayName("Get All Members")
|
||||||
|
.HasApiVersion(1.0)
|
||||||
|
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser());
|
||||||
|
|
||||||
|
group.MapPost("", PostMemberAsync)
|
||||||
|
.WithDisplayName("Post Member")
|
||||||
|
.HasApiVersion(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IResult> GetAllMembersAsync([FromQuery] int page, [FromServices] IMediator mediator, CancellationToken cancellationToken)
|
||||||
|
=> TypedResults.Ok(await mediator.Send(new GetNewsletterMembersQuery(page), cancellationToken));
|
||||||
|
|
||||||
|
public async Task<IResult> PostMemberAsync([FromBody]CreateNewsletterMemberCommand request, [FromServices] IMediator mediator, CancellationToken cancellationToken)
|
||||||
|
=> TypedResults.Ok(await mediator.Send(request, cancellationToken));
|
||||||
|
}
|
|
@ -6,8 +6,8 @@
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<InvariantGlobalization>true</InvariantGlobalization>
|
<InvariantGlobalization>true</InvariantGlobalization>
|
||||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
<AssemblyVersion>0.7.14.22</AssemblyVersion>
|
<AssemblyVersion>0.8.15.22</AssemblyVersion>
|
||||||
<FileVersion>0.7.14.22</FileVersion>
|
<FileVersion>0.8.15.22</FileVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
namespace NetinaShop.Domain.CommandQueries.Commands;
|
||||||
|
|
||||||
|
public sealed record CreateNewsletterMemberCommand(string PhoneNumber,string Email) : IRequest<bool>;
|
||||||
|
public sealed record DeleteNewsletterMemberCommand(Guid Id) : IRequest<bool>;
|
|
@ -0,0 +1,3 @@
|
||||||
|
namespace NetinaShop.Domain.CommandQueries.Queries;
|
||||||
|
|
||||||
|
public sealed record GetNewsletterMembersQuery(int Page = 0) : IRequest<List<NewsletterMemberSDto>>;
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace NetinaShop.Domain.Dtos.SmallDtos;
|
||||||
|
|
||||||
|
public class NewsletterMemberSDto : BaseDto<NewsletterMemberSDto,NewsletterMember>
|
||||||
|
{
|
||||||
|
public string PhoneNumber { get; set; } = string.Empty;
|
||||||
|
public string Email { get; set; } = string.Empty;
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
namespace NetinaShop.Domain.Entities.Users;
|
||||||
|
|
||||||
|
[AdaptTwoWays("[name]LDto", IgnoreAttributes = new[] { typeof(AdaptIgnoreAttribute) }, MapType = MapType.Map | MapType.MapToTarget | MapType.Projection)]
|
||||||
|
[AdaptTwoWays("[name]SDto", IgnoreAttributes = new[] { typeof(AdaptIgnoreAttribute) }, MapType = MapType.Map | MapType.MapToTarget)]
|
||||||
|
[AdaptTo("[name]SDto", IgnoreAttributes = new[] { typeof(AdaptIgnoreAttribute) }, MapType = MapType.Projection)]
|
||||||
|
[GenerateMapper]
|
||||||
|
public partial class NewsletterMember : ApiEntity
|
||||||
|
{
|
||||||
|
public NewsletterMember()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
public NewsletterMember(string phoneNumber, string email)
|
||||||
|
{
|
||||||
|
PhoneNumber = phoneNumber;
|
||||||
|
Email = email;
|
||||||
|
}
|
||||||
|
public string PhoneNumber { get; internal set; } = string.Empty;
|
||||||
|
public string Email { get; internal set; } = string.Empty;
|
||||||
|
|
||||||
|
}
|
|
@ -11,3 +11,11 @@ public partial class UserAddress
|
||||||
userId);
|
userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public partial class NewsletterMember
|
||||||
|
{
|
||||||
|
public static NewsletterMember Create(string phoneNumber, string email)
|
||||||
|
{
|
||||||
|
return new NewsletterMember(phoneNumber, email);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using NetinaShop.Domain.Dtos.SmallDtos;
|
||||||
|
using NetinaShop.Domain.Entities.Users;
|
||||||
|
|
||||||
|
namespace NetinaShop.Domain.Mappers
|
||||||
|
{
|
||||||
|
public static partial class NewsletterMemberMapper
|
||||||
|
{
|
||||||
|
public static NewsletterMember AdaptToNewsletterMember(this NewsletterMemberSDto p1)
|
||||||
|
{
|
||||||
|
return p1 == null ? null : new NewsletterMember()
|
||||||
|
{
|
||||||
|
PhoneNumber = p1.PhoneNumber,
|
||||||
|
Email = p1.Email,
|
||||||
|
Id = p1.Id,
|
||||||
|
CreatedAt = p1.CreatedAt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static NewsletterMember AdaptTo(this NewsletterMemberSDto p2, NewsletterMember p3)
|
||||||
|
{
|
||||||
|
if (p2 == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
NewsletterMember result = p3 ?? new NewsletterMember();
|
||||||
|
|
||||||
|
result.PhoneNumber = p2.PhoneNumber;
|
||||||
|
result.Email = p2.Email;
|
||||||
|
result.Id = p2.Id;
|
||||||
|
result.CreatedAt = p2.CreatedAt;
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
public static NewsletterMemberSDto AdaptToSDto(this NewsletterMember p4)
|
||||||
|
{
|
||||||
|
return p4 == null ? null : new NewsletterMemberSDto()
|
||||||
|
{
|
||||||
|
PhoneNumber = p4.PhoneNumber,
|
||||||
|
Email = p4.Email,
|
||||||
|
Id = p4.Id,
|
||||||
|
CreatedAt = p4.CreatedAt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public static NewsletterMemberSDto AdaptTo(this NewsletterMember p5, NewsletterMemberSDto p6)
|
||||||
|
{
|
||||||
|
if (p5 == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
NewsletterMemberSDto result = p6 ?? new NewsletterMemberSDto();
|
||||||
|
|
||||||
|
result.PhoneNumber = p5.PhoneNumber;
|
||||||
|
result.Email = p5.Email;
|
||||||
|
result.Id = p5.Id;
|
||||||
|
result.CreatedAt = p5.CreatedAt;
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
public static Expression<Func<NewsletterMember, NewsletterMemberSDto>> ProjectToSDto => p7 => new NewsletterMemberSDto()
|
||||||
|
{
|
||||||
|
PhoneNumber = p7.PhoneNumber,
|
||||||
|
Email = p7.Email,
|
||||||
|
Id = p7.Id,
|
||||||
|
CreatedAt = p7.CreatedAt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace NetinaShop.Repository.Handlers.Newsletters;
|
||||||
|
|
||||||
|
public class CreateNewsletterMemberCommandHandler : IRequestHandler<CreateNewsletterMemberCommand,bool>
|
||||||
|
{
|
||||||
|
private readonly IRepositoryWrapper _repositoryWrapper;
|
||||||
|
|
||||||
|
public CreateNewsletterMemberCommandHandler(IRepositoryWrapper repositoryWrapper)
|
||||||
|
{
|
||||||
|
_repositoryWrapper = repositoryWrapper;
|
||||||
|
}
|
||||||
|
public async Task<bool> Handle(CreateNewsletterMemberCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (request.PhoneNumber.IsNullOrEmpty() && request.Email.IsNullOrEmpty())
|
||||||
|
throw new AppException("PhoneNumber and Email is null");
|
||||||
|
if (!request.PhoneNumber.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
var existedPhoneNumber = await _repositoryWrapper.SetRepository<NewsletterMember>()
|
||||||
|
.TableNoTracking
|
||||||
|
.AnyAsync(c => c.PhoneNumber == request.PhoneNumber, cancellationToken);
|
||||||
|
if (existedPhoneNumber == true)
|
||||||
|
throw new AppException("PhoneNumber is existed");
|
||||||
|
}
|
||||||
|
if (!request.Email.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
var existedEmail = await _repositoryWrapper.SetRepository<NewsletterMember>()
|
||||||
|
.TableNoTracking
|
||||||
|
.AnyAsync(c => c.Email == request.Email, cancellationToken);
|
||||||
|
if (existedEmail == true)
|
||||||
|
throw new AppException("Email is existed");
|
||||||
|
}
|
||||||
|
|
||||||
|
var ent = NewsletterMember.Create(request.PhoneNumber, request.Email);
|
||||||
|
_repositoryWrapper.SetRepository<NewsletterMember>()
|
||||||
|
.Add(ent);
|
||||||
|
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace NetinaShop.Repository.Handlers.Newsletters;
|
||||||
|
|
||||||
|
public class GetNewsletterMembersQueryHandler : IRequestHandler<GetNewsletterMembersQuery,List<NewsletterMemberSDto>>
|
||||||
|
{
|
||||||
|
private readonly IRepositoryWrapper _repositoryWrapper;
|
||||||
|
|
||||||
|
public GetNewsletterMembersQueryHandler(IRepositoryWrapper repositoryWrapper)
|
||||||
|
{
|
||||||
|
_repositoryWrapper = repositoryWrapper;
|
||||||
|
}
|
||||||
|
public async Task<List<NewsletterMemberSDto>> Handle(GetNewsletterMembersQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var dtos = await _repositoryWrapper.SetRepository<NewsletterMember>()
|
||||||
|
.TableNoTracking
|
||||||
|
.OrderByDescending(n => n.CreatedAt)
|
||||||
|
.Select(NewsletterMemberMapper.ProjectToSDto)
|
||||||
|
.Skip(request.Page * 20)
|
||||||
|
.Take(20)
|
||||||
|
.ToListAsync(cancellationToken);
|
||||||
|
return dtos;
|
||||||
|
}
|
||||||
|
}
|
1729
NetinaShop.Repository/Migrations/20240222192632_AddNewsletterMember.Designer.cs
generated
100644
1729
NetinaShop.Repository/Migrations/20240222192632_AddNewsletterMember.Designer.cs
generated
100644
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,44 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace NetinaShop.Repository.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddNewsletterMember : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "NewsletterMembers",
|
||||||
|
schema: "public",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
PhoneNumber = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Email = table.Column<string>(type: "text", nullable: false),
|
||||||
|
RemovedAt = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
|
||||||
|
CreatedBy = table.Column<string>(type: "text", nullable: true),
|
||||||
|
IsRemoved = table.Column<bool>(type: "boolean", nullable: false),
|
||||||
|
RemovedBy = table.Column<string>(type: "text", nullable: true),
|
||||||
|
ModifiedAt = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
|
||||||
|
ModifiedBy = table.Column<string>(type: "text", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_NewsletterMembers", x => x.Id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "NewsletterMembers",
|
||||||
|
schema: "public");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1105,6 +1105,46 @@ namespace NetinaShop.Repository.Migrations
|
||||||
b.ToTable("Users", "public");
|
b.ToTable("Users", "public");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NetinaShop.Domain.Entities.Users.NewsletterMember", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp without time zone");
|
||||||
|
|
||||||
|
b.Property<string>("CreatedBy")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<bool>("IsRemoved")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTime>("ModifiedAt")
|
||||||
|
.HasColumnType("timestamp without time zone");
|
||||||
|
|
||||||
|
b.Property<string>("ModifiedBy")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("PhoneNumber")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime>("RemovedAt")
|
||||||
|
.HasColumnType("timestamp without time zone");
|
||||||
|
|
||||||
|
b.Property<string>("RemovedBy")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("NewsletterMembers", "public");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NetinaShop.Domain.Entities.Users.UserAddress", b =>
|
modelBuilder.Entity("NetinaShop.Domain.Entities.Users.UserAddress", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
|
|
Loading…
Reference in New Issue