feat : add newsletter and newsletter members , add version 0.8.15.22

add needed controller and models , fix sidebar in responsive
release
Amir Hossein Khademi 2024-02-24 15:39:25 +03:30
parent 348051c391
commit 75d53a7f76
15 changed files with 2017 additions and 4 deletions

View File

@ -1 +1 @@
0.7.14.22
0.8.15.22

View File

@ -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",

View File

@ -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));
}

View File

@ -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>

View File

@ -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>;

View File

@ -0,0 +1,3 @@
namespace NetinaShop.Domain.CommandQueries.Queries;
public sealed record GetNewsletterMembersQuery(int Page = 0) : IRequest<List<NewsletterMemberSDto>>;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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
};
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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");
}
}
}

View File

@ -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")