version 0.27.33.54 , fix blog update issue , fix sitemap , fix page creation

release
Amir Hossein Khademi 2024-05-14 12:46:11 +03:30
parent 5a38eda328
commit c152f06e08
15 changed files with 146 additions and 50 deletions

View File

@ -1 +1 @@
0.27.32.53 0.27.33.54

View File

@ -82,6 +82,8 @@ public class BlogCategoryController : ICarterModule
if (dto.ParentId != default) if (dto.ParentId != default)
ent.SetParent(dto.ParentId); ent.SetParent(dto.ParentId);
newEnt.Id = ent.Id; newEnt.Id = ent.Id;
newEnt.CreatedAt = ent.CreatedAt;
newEnt.CreatedBy = ent.CreatedBy;
repositoryWrapper.SetRepository<BlogCategory>().Update(newEnt); repositoryWrapper.SetRepository<BlogCategory>().Update(newEnt);
await repositoryWrapper.SaveChangesAsync(cancellationToken); await repositoryWrapper.SaveChangesAsync(cancellationToken);
return TypedResults.Ok(); return TypedResults.Ok();

View File

@ -74,6 +74,8 @@ public class BlogController : ICarterModule
throw new AppException("Blog not found"); throw new AppException("Blog not found");
var newEnt = Blog.Create(dto.Title, dto.Content, dto.Tags, dto.ReadingTime, dto.Summery, dto.IsSuggested, dto.CategoryId); var newEnt = Blog.Create(dto.Title, dto.Content, dto.Tags, dto.ReadingTime, dto.Summery, dto.IsSuggested, dto.CategoryId);
newEnt.Id = ent.Id; newEnt.Id = ent.Id;
newEnt.CreatedAt = ent.CreatedAt;
newEnt.CreatedBy = ent.CreatedBy;
repositoryWrapper.SetRepository<Blog>().Update(newEnt); repositoryWrapper.SetRepository<Blog>().Update(newEnt);
await repositoryWrapper.SaveChangesAsync(cancellationToken); await repositoryWrapper.SaveChangesAsync(cancellationToken);
return TypedResults.Ok(); return TypedResults.Ok();

View File

@ -31,8 +31,19 @@ public class PageController : ICarterModule
.WithDisplayName("Post Page") .WithDisplayName("Post Page")
.HasApiVersion(1.0) .HasApiVersion(1.0)
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission, ApplicationPermission.ManagePages)); .RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission, ApplicationPermission.ManagePages));
group.MapDelete("{id}", DeletePageByIdAsync)
.WithDisplayName("Delete Page")
.HasApiVersion(1.0)
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser().RequireClaim(CustomClaimType.Permission, ApplicationPermission.ViewPages, ApplicationPermission.ManagePages));
} }
public async Task<IResult> GetPagesAsync(Guid id, [FromServices] IPageService pageService, CancellationToken cancellationToken)
private async Task<IResult> DeletePageByIdAsync([FromRoute]Guid id,[FromServices]IPageService pageService,CancellationToken cancellationToken)
=> TypedResults.Ok(await pageService.DeletePageAsync(id, cancellationToken));
public async Task<IResult> GetPagesAsync([FromServices] IPageService pageService, CancellationToken cancellationToken)
{ {
return TypedResults.Ok(await pageService.GetPagesAsync(cancellationToken)); return TypedResults.Ok(await pageService.GetPagesAsync(cancellationToken));
} }

View File

@ -6,8 +6,8 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization> <InvariantGlobalization>true</InvariantGlobalization>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS> <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<AssemblyVersion>0.27.31.52</AssemblyVersion> <AssemblyVersion>0.27.33.54</AssemblyVersion>
<FileVersion>0.27.31.52</FileVersion> <FileVersion>0.27.33.54</FileVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -8,7 +8,7 @@ string env = builder.Environment.IsDevelopment() == true ? "Development" : "Prod
builder.Host.UseContentRoot(Directory.GetCurrentDirectory()); builder.Host.UseContentRoot(Directory.GetCurrentDirectory());
if (builder.Environment.IsDevelopment()) if (builder.Environment.IsDevelopment())
{ {
string projectName = "Hamyan"; string projectName = "Vesmeh";
builder.Configuration.AddJsonFile($"AppSettings/appsettings.json").AddJsonFile($"AppSettings/appsettings.{env}{projectName}.json"); builder.Configuration.AddJsonFile($"AppSettings/appsettings.json").AddJsonFile($"AppSettings/appsettings.{env}{projectName}.json");
} }

View File

@ -12,12 +12,17 @@ public class SiteMapService : ISiteMapService
{ {
private readonly IUploadFileService _uploadFileService; private readonly IUploadFileService _uploadFileService;
private readonly IRepositoryWrapper _repositoryWrapper; private readonly IRepositoryWrapper _repositoryWrapper;
private readonly IPageService _pageService;
private readonly SiteSettings _siteSetting; private readonly SiteSettings _siteSetting;
public SiteMapService(IOptionsSnapshot<SiteSettings> snapshot, IUploadFileService uploadFileService, IRepositoryWrapper repositoryWrapper) public SiteMapService(IOptionsSnapshot<SiteSettings> snapshot,
IUploadFileService uploadFileService,
IRepositoryWrapper repositoryWrapper,
IPageService pageService)
{ {
_uploadFileService = uploadFileService; _uploadFileService = uploadFileService;
_repositoryWrapper = repositoryWrapper; _repositoryWrapper = repositoryWrapper;
_pageService = pageService;
_siteSetting = snapshot.Value; _siteSetting = snapshot.Value;
} }
public async Task CreateSiteMapAsync() public async Task CreateSiteMapAsync()
@ -106,10 +111,77 @@ public class SiteMapService : ISiteMapService
await CreateBlogsSiteMapsAsync(); await CreateBlogsSiteMapsAsync();
await CreateBrandsSiteMapsAsync(); await CreateBrandsSiteMapsAsync();
await CreateBlogCategoriesSiteMapsAsync(); await CreateBlogCategoriesSiteMapsAsync();
await CreatePagesSiteMapsAsync();
} }
private async Task CreatePagesSiteMapsAsync()
{
var siteMapsUId = SiteMapUIds.Pages;
var pages = await _pageService.GetPagesAsync();
XmlDocument doc = new XmlDocument();
XmlDeclaration documentType = doc.CreateXmlDeclaration("1.0", "utf-8", null);
doc.AppendChild(documentType);
//XmlNode declaration = doc.CreateNode(XmlNodeType.XmlDeclaration, "sitemap.xml", null);
//doc.AppendChild(declaration);
XmlElement root = doc.CreateElement("urlset", "http://www.sitemaps.org/schemas/sitemap/0.9");
root.SetAttribute("xmlns:image", "http://www.google.com/schemas/sitemap-image/1.1");
doc.AppendChild(root);
foreach (var page in pages)
{
var productUrl = $"{_siteSetting.WebSiteUrl}/{page.Slug}";
XmlElement urlElement = doc.CreateElement("url", doc.DocumentElement?.NamespaceURI);
root.AppendChild(urlElement);
XmlElement loc = doc.CreateElement("loc", doc.DocumentElement?.NamespaceURI);
loc.InnerText = Path.Combine(productUrl);
urlElement.AppendChild(loc);
XmlElement lastmod = doc.CreateElement("lastmod", doc.DocumentElement?.NamespaceURI);
lastmod.InnerText = page.ModifiedAt == DateTime.MinValue ? page.CreatedAt.ToString("yyyy-MM-dd") : page.ModifiedAt.ToString("yyyy-MM-dd");
urlElement.AppendChild(lastmod);
XmlElement changeFeq = doc.CreateElement("changefreq", doc.DocumentElement?.NamespaceURI);
changeFeq.InnerText = "weekly";
urlElement.AppendChild(changeFeq);
XmlElement priority = doc.CreateElement("priority", doc.DocumentElement?.NamespaceURI);
priority.InnerText = "0.8";
urlElement.AppendChild(priority);
}
using var siteMapStream = new MemoryStream();
await using var siteMapWriter = new XmlTextWriter(siteMapStream, Encoding.UTF8);
doc.WriteTo(siteMapWriter);
siteMapWriter.Flush();
byte[] unZipBytes = siteMapStream.ToArray();
using (var compressedStream = new MemoryStream())
await using (var zipStream = new GZipStream(compressedStream, CompressionMode.Compress))
{
zipStream.Write(unZipBytes, 0, unZipBytes.Length);
zipStream.Close();
var siteMapArray = compressedStream.ToArray();
await _uploadFileService.UploadFileByteAsync(new FileUploadRequest
{
FileBytes = siteMapArray,
ContentType = "text/plain",
FileName = $"{siteMapsUId}.gz",
FileUploadType = FileUploadType.SiteMap,
});
}
}
private async Task CreateBrandsSiteMapsAsync() private async Task CreateBrandsSiteMapsAsync()
{ {
var siteMapsUId = SiteMapUIds.Brands; var siteMapsUId = SiteMapUIds.Brands;

View File

@ -1,12 +1,9 @@
using Netina.Common.Models; namespace Netina.Core.CoreServices.Abstracts;
using Netina.Domain.Dtos.RequestDtos;
using Netina.Domain.Dtos.SmallDtos;
namespace Netina.Core.CoreServices.Abstracts;
public interface IPageService : IScopedDependency public interface IPageService : IScopedDependency
{ {
Task<BasePageSDto> GetPageAsync(Guid? id = null, string? pageName = null, string? pageSlug = null,string? type = null, CancellationToken cancellationToken=default); Task<BasePageSDto> GetPageAsync(Guid? id = null, string? pageName = null, string? pageSlug = null,string? type = null, CancellationToken cancellationToken=default);
Task<List<BasePageSDto>> GetPagesAsync(CancellationToken cancellationToken = default); Task<List<BasePageSDto>> GetPagesAsync(CancellationToken cancellationToken = default);
Task<bool> CreatePageAsync(PageActionRequestDto entity, CancellationToken cancellationToken = default); Task<bool> CreatePageAsync(PageActionRequestDto entity, CancellationToken cancellationToken = default);
Task<bool> DeletePageAsync(Guid id,CancellationToken cancellationToken = default);
} }

View File

@ -1,21 +1,16 @@
using Netina.Common.Models.Api; using Netina.Domain.MartenEntities.Pages;
using Netina.Common.Models.Exception;
using Netina.Core.CoreServices.Abstracts;
using Netina.Domain;
using Netina.Domain.Dtos.RequestDtos;
using Netina.Domain.Dtos.SmallDtos;
using Netina.Domain.MartenEntities.Pages;
using Netina.Repository.Repositories.Marten;
namespace Netina.Core.CoreServices; namespace Netina.Core.CoreServices;
public class PageService : IPageService public class PageService : IPageService
{ {
private readonly IMartenRepositoryWrapper _martenRepositoryWrapper; private readonly IMartenRepositoryWrapper _martenRepositoryWrapper;
private readonly ICurrentUserService _currentUserService;
public PageService(IMartenRepositoryWrapper martenRepositoryWrapperWrapper) public PageService(IMartenRepositoryWrapper martenRepositoryWrapperWrapper, ICurrentUserService currentUserService)
{ {
_martenRepositoryWrapper = martenRepositoryWrapperWrapper; _martenRepositoryWrapper = martenRepositoryWrapperWrapper;
_currentUserService = currentUserService;
} }
public async Task<BasePageSDto> GetPageAsync(Guid? id = null, string? pageName = null, string? pageSlug = null, string? type = null, CancellationToken cancellationToken = default) public async Task<BasePageSDto> GetPageAsync(Guid? id = null, string? pageName = null, string? pageSlug = null, string? type = null, CancellationToken cancellationToken = default)
{ {
@ -25,7 +20,7 @@ public class PageService : IPageService
else if (pageSlug != null) else if (pageSlug != null)
page = await _martenRepositoryWrapper.SetRepository<BasePage>().GetEntityAsync(entity => entity.Slug == pageSlug, cancellationToken); page = await _martenRepositoryWrapper.SetRepository<BasePage>().GetEntityAsync(entity => entity.Slug == pageSlug, cancellationToken);
else if (pageName != null) else if (pageName != null)
page = await _martenRepositoryWrapper.SetRepository<BasePage>().GetEntityAsync(entity => entity.Name == pageName, cancellationToken); page = await _martenRepositoryWrapper.SetRepository<BasePage>().GetEntityAsync(entity => entity.Title == pageName, cancellationToken);
else if (type != null) else if (type != null)
page = await _martenRepositoryWrapper.SetRepository<BasePage>().GetEntityAsync(entity => entity.Type == type, cancellationToken); page = await _martenRepositoryWrapper.SetRepository<BasePage>().GetEntityAsync(entity => entity.Type == type, cancellationToken);
if (page == null) if (page == null)
@ -39,7 +34,7 @@ public class PageService : IPageService
Id = page.Id, Id = page.Id,
IsCustomPage = page.IsCustomPage, IsCustomPage = page.IsCustomPage,
IsHtmlBasePage = page.IsHtmlBasePage, IsHtmlBasePage = page.IsHtmlBasePage,
Name = page.Name, Title = page.Title,
Slug = page.Slug, Slug = page.Slug,
Data = page.Data Data = page.Data
}; };
@ -53,8 +48,6 @@ public class PageService : IPageService
var pages = await _martenRepositoryWrapper.SetRepository<BasePage>().GetEntitiesAsync(cancellationToken); var pages = await _martenRepositoryWrapper.SetRepository<BasePage>().GetEntitiesAsync(cancellationToken);
foreach (var page in pages) foreach (var page in pages)
{ {
var type = Assembly.GetAssembly(typeof(DomainConfig))?.GetType(page.Type);
var dto = new BasePageSDto var dto = new BasePageSDto
{ {
Content = page.Content, Content = page.Content,
@ -62,9 +55,11 @@ public class PageService : IPageService
Id = page.Id, Id = page.Id,
IsCustomPage = page.IsCustomPage, IsCustomPage = page.IsCustomPage,
IsHtmlBasePage = page.IsHtmlBasePage, IsHtmlBasePage = page.IsHtmlBasePage,
Name = page.Name, Title = page.Title,
Slug = page.Slug, Slug = page.Slug,
Data = page.Data Data = page.Data,
CreatedAt = page.CreatedAt,
ModifiedAt = page.ModifiedAt
}; };
sDtos.Add(dto); sDtos.Add(dto);
} }
@ -77,16 +72,30 @@ public class PageService : IPageService
{ {
Content = entity.Content, Content = entity.Content,
Description = entity.Description, Description = entity.Description,
Id = entity.Id, Id = Guid.NewGuid(),
IsCustomPage = entity.IsCustomPage, IsCustomPage = entity.IsCustomPage,
IsHtmlBasePage = entity.IsHtmlBasePage, IsHtmlBasePage = entity.IsHtmlBasePage,
Name = entity.Name, Title = entity.Title,
Type = entity.Type, Type = entity.Type,
Slug = entity.Slug, Slug = entity.Slug,
CreatedAt = DateTime.Now,
CreatedBy = _currentUserService.UserName ?? string.Empty
}; };
var type = Assembly.GetAssembly(typeof(DomainConfig))?.GetType(entity.Type); if (!basePage.Type.IsNullOrEmpty())
basePage.Data = JsonConvert.SerializeObject(((JsonElement)entity.Data).Deserialize(type)); {
var type = Assembly.GetAssembly(typeof(DomainConfig))?.GetType(entity.Type);
basePage.Data = JsonConvert.SerializeObject(((JsonElement)entity.Data).Deserialize(type));
}
await _martenRepositoryWrapper.SetRepository<BasePage>().AddOrUpdateEntityAsync(basePage, cancellationToken); await _martenRepositoryWrapper.SetRepository<BasePage>().AddOrUpdateEntityAsync(basePage, cancellationToken);
return true; return true;
} }
public async Task<bool> DeletePageAsync(Guid id, CancellationToken cancellationToken = default)
{
var page = await _martenRepositoryWrapper.SetRepository<BasePage>().GetEntityAsync(p => p.Id == id, cancellationToken);
if (page == null)
throw new AppException("Page not found", ApiResultStatusCode.NotFound);
await _martenRepositoryWrapper.SetRepository<BasePage>().RemoveEntityAsync(page,cancellationToken);
return true;
}
} }

View File

@ -5,12 +5,14 @@ public static class SiteMapUIds
public const string Brands = "662AF2DC6A2746FA88191F1F3DA94164"; public const string Brands = "662AF2DC6A2746FA88191F1F3DA94164";
public const string Blogs = "4C2F0C2A7A3E41268702D12FDDDB837F"; public const string Blogs = "4C2F0C2A7A3E41268702D12FDDDB837F";
public const string BlogCategories = "B5FF333DC4FF4BB4A309CE3AA32CE45A"; public const string BlogCategories = "B5FF333DC4FF4BB4A309CE3AA32CE45A";
public const string Pages = "B463B6C4CC53432C822D79934F528D3E";
public static List<string> AllSiteMapsUIds => new List<string> public static List<string> AllSiteMapsUIds => new List<string>
{ {
BlogCategories, BlogCategories,
Categories, Categories,
Blogs, Blogs,
Brands Brands,
Pages
}; };
} }

View File

@ -3,7 +3,7 @@
public class PageActionRequestDto public class PageActionRequestDto
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public string Name { get; set; } = string.Empty; public string Title { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty; public string Description { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty; public string Content { get; set; } = string.Empty;
public bool IsCustomPage { get; set; } public bool IsCustomPage { get; set; }

View File

@ -5,13 +5,14 @@ namespace Netina.Domain.Dtos.SmallDtos;
public class BasePageSDto : BaseDto<BasePageSDto,BasePage> public class BasePageSDto : BaseDto<BasePageSDto,BasePage>
{ {
public string Name { get; set; } = string.Empty; public string Title { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty; public string Description { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty; public string Content { get; set; } = string.Empty;
public bool IsCustomPage { get; set; } public bool IsCustomPage { get; set; }
public bool IsHtmlBasePage { get; set; } public bool IsHtmlBasePage { get; set; }
public string Slug { get; set; } = string.Empty; public string Slug { get; set; } = string.Empty;
public string Data { get; set; } = string.Empty; public string Data { get; set; } = string.Empty;
public DateTime ModifiedAt { get; set; }
public T GetData<T>() => JsonConvert.DeserializeObject<T>(Data); public T GetData<T>() => JsonConvert.DeserializeObject<T>(Data);
} }

View File

@ -2,7 +2,7 @@
public class BasePage : MartenEntity public class BasePage : MartenEntity
{ {
public string Name { get; set; } = string.Empty; public string Title { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty; public string Description { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty; public string Content { get; set; } = string.Empty;
public bool IsCustomPage { get; set; } public bool IsCustomPage { get; set; }

View File

@ -1,8 +1,4 @@
using Marten; using Marten;
using Netina.Common.Models.Api;
using Netina.Common.Models.Entity;
using Netina.Common.Models.Exception;
using Netina.Repository.Repositories.Marten;
namespace Netina.Infrastructure.Marten; namespace Netina.Infrastructure.Marten;
@ -45,18 +41,22 @@ public class MartenRepository<TMartenEntity> : IMartenRepository<TMartenEntity>
return entity; return entity;
} }
public async Task AddOrUpdateEntityAsync(TMartenEntity setting, CancellationToken cancellation) public async Task AddOrUpdateEntityAsync(TMartenEntity entity, CancellationToken cancellation)
{ {
if (setting == null) if (entity == null)
throw new AppException($"{nameof(setting)} is null", ApiResultStatusCode.BadRequest); throw new AppException($"{nameof(entity)} is null", ApiResultStatusCode.BadRequest);
await using var session = _documentStore.LightweightSession(); await using var session = _documentStore.LightweightSession();
session.Store(setting); session.Store(entity);
await session.SaveChangesAsync(cancellation); await session.SaveChangesAsync(cancellation);
} }
public Task RemoveEntityAsync(CancellationToken cancellation) public async Task RemoveEntityAsync(TMartenEntity entity, CancellationToken cancellation)
{ {
throw new NotImplementedException(); if (entity == null)
throw new AppException($"{nameof(entity)} is null", ApiResultStatusCode.BadRequest);
await using var session = _documentStore.LightweightSession();
session.Delete(entity);
await session.SaveChangesAsync(cancellation);
} }
} }

View File

@ -4,12 +4,12 @@ namespace Netina.Repository.Repositories.Marten;
public interface IMartenRepository<TMartenEntity> : IScopedDependency where TMartenEntity : IMartenEntity public interface IMartenRepository<TMartenEntity> : IScopedDependency where TMartenEntity : IMartenEntity
{ {
Task<List<TMartenEntity>> GetEntitiesAsync(CancellationToken cancellation); Task<List<TMartenEntity>> GetEntitiesAsync(CancellationToken cancellation = default);
Task<List<TMartenEntity>> GetEntitiesAsync(Expression<Func<TMartenEntity, bool>> expression, CancellationToken cancellation); Task<List<TMartenEntity>> GetEntitiesAsync(Expression<Func<TMartenEntity, bool>> expression, CancellationToken cancellation = default);
Task<TMartenEntity> GetEntityAsync(Guid id, CancellationToken cancellation); Task<TMartenEntity> GetEntityAsync(Guid id, CancellationToken cancellation = default);
Task<TMartenEntity?> GetEntityAsync(Expression<Func<TMartenEntity, bool>> expression, CancellationToken cancellation); Task<TMartenEntity?> GetEntityAsync(Expression<Func<TMartenEntity, bool>> expression, CancellationToken cancellation = default);
Task AddOrUpdateEntityAsync(TMartenEntity setting, CancellationToken cancellation); Task AddOrUpdateEntityAsync(TMartenEntity entity, CancellationToken cancellation = default);
Task RemoveEntityAsync(CancellationToken cancellation); Task RemoveEntityAsync(TMartenEntity entity, CancellationToken cancellation = default);
} }