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
|
||||
},
|
||||
"SiteSettings": {
|
||||
"BaseUrl": "http://192.168.88.17:32770",
|
||||
"BaseUrl": "http://192.168.88.251:32770",
|
||||
"KaveNegarApiKey": "3735494B4143727A794346457461576A2B4B6668414973424E333561505A694B",
|
||||
"UserSetting": {
|
||||
"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>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<AssemblyVersion>0.7.14.22</AssemblyVersion>
|
||||
<FileVersion>0.7.14.22</FileVersion>
|
||||
<AssemblyVersion>0.8.15.22</AssemblyVersion>
|
||||
<FileVersion>0.8.15.22</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<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;
|
||||
|
||||
}
|
|
@ -10,4 +10,12 @@ public partial class UserAddress
|
|||
locationLat, locationLong, province, city, plaque, buildingUnit,
|
||||
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");
|
||||
});
|
||||
|
||||
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 =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
|
|
Loading…
Reference in New Issue