|
|
@@ -0,0 +1,276 @@
|
|
|
+using Common;
|
|
|
+using Common.Constant;
|
|
|
+using Common.Http;
|
|
|
+using Esim.Apis.Singleton;
|
|
|
+using Database.Database;
|
|
|
+using log4net;
|
|
|
+using Microsoft.AspNetCore.Mvc;
|
|
|
+using Newtonsoft.Json;
|
|
|
+
|
|
|
+namespace Esim.Apis.Business
|
|
|
+{
|
|
|
+ public class ArticleBusinessImpl : IArticleBusiness
|
|
|
+ {
|
|
|
+ private static readonly log4net.ILog log = log4net.LogManager.GetLogger(
|
|
|
+ typeof(ArticleBusinessImpl)
|
|
|
+ );
|
|
|
+
|
|
|
+ private ModelContext dbContext;
|
|
|
+ IConfiguration configuration;
|
|
|
+
|
|
|
+ public ArticleBusinessImpl(ModelContext _dbContext, IConfiguration _configuration)
|
|
|
+ {
|
|
|
+ dbContext = _dbContext;
|
|
|
+ configuration = _configuration;
|
|
|
+ }
|
|
|
+
|
|
|
+ private string GetParameter(string key)
|
|
|
+ {
|
|
|
+ return configuration.GetSection(key).Value ?? "";
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Load article categories with pagination
|
|
|
+ /// </summary>
|
|
|
+ public async Task<IActionResult> ArticleCategory(HttpRequest httpRequest, ArticleCategoryReq request)
|
|
|
+ {
|
|
|
+ var url = httpRequest.Path;
|
|
|
+ var json = JsonConvert.SerializeObject(request);
|
|
|
+ log.Debug("URL: " + url + " => Request: " + json);
|
|
|
+ try
|
|
|
+ {
|
|
|
+ string lang = (request.lang ?? "lo").ToLower();
|
|
|
+ int pageNumber = request.pageNumber < 0 ? 0 : request.pageNumber;
|
|
|
+ int pageSize = request.pageSize <= 0 ? 10 : request.pageSize;
|
|
|
+
|
|
|
+ // Query categories
|
|
|
+ var query = dbContext.ArticleCategories
|
|
|
+ .Where(c => c.Status == true);
|
|
|
+
|
|
|
+ // Filter by parent category
|
|
|
+ if (request.parentId.HasValue)
|
|
|
+ {
|
|
|
+ query = query.Where(c => c.ParentId == request.parentId);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ query = query.Where(c => c.ParentId == null); // Root categories
|
|
|
+ }
|
|
|
+
|
|
|
+ // Get total count for pagination
|
|
|
+ int totalCount = query.Count();
|
|
|
+ int totalPages = (int)Math.Ceiling((double)totalCount / pageSize);
|
|
|
+
|
|
|
+ // Apply pagination and ordering
|
|
|
+ var categories = query
|
|
|
+ .OrderBy(c => c.DisplayOrder)
|
|
|
+ .ThenBy(c => c.Id)
|
|
|
+ .Skip(pageNumber * pageSize)
|
|
|
+ .Take(pageSize)
|
|
|
+ .Select(c => new
|
|
|
+ {
|
|
|
+ c.Id,
|
|
|
+ categoryName = lang == "en"
|
|
|
+ ? (c.CategoryNameEn ?? c.CategoryName)
|
|
|
+ : (c.CategoryNameLo ?? c.CategoryName),
|
|
|
+ c.CategorySlug,
|
|
|
+ description = lang == "en"
|
|
|
+ ? (c.DescriptionEn ?? c.Description)
|
|
|
+ : (c.DescriptionLo ?? c.Description),
|
|
|
+ c.IconUrl,
|
|
|
+ c.ParentId,
|
|
|
+ c.DisplayOrder
|
|
|
+ })
|
|
|
+ .ToList();
|
|
|
+
|
|
|
+ return DotnetLib.Http.HttpResponse.BuildResponse(
|
|
|
+ log,
|
|
|
+ url,
|
|
|
+ json,
|
|
|
+ CommonErrorCode.Success,
|
|
|
+ ConfigManager.Instance.GetConfigWebValue("LOAD_SUCCESS", lang),
|
|
|
+ new
|
|
|
+ {
|
|
|
+ items = categories,
|
|
|
+ pagination = new
|
|
|
+ {
|
|
|
+ pageNumber,
|
|
|
+ pageSize,
|
|
|
+ totalCount,
|
|
|
+ totalPages
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ }
|
|
|
+ catch (Exception exception)
|
|
|
+ {
|
|
|
+ log.Error("Exception: ", exception);
|
|
|
+ }
|
|
|
+ return DotnetLib.Http.HttpResponse.BuildResponse(
|
|
|
+ log,
|
|
|
+ url,
|
|
|
+ json,
|
|
|
+ CommonErrorCode.SystemError,
|
|
|
+ ConfigManager.Instance.GetConfigWebValue("SYSTEM_FAILURE"),
|
|
|
+ new { }
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Load articles with pagination and filters
|
|
|
+ /// </summary>
|
|
|
+ public async Task<IActionResult> ArticleLoad(HttpRequest httpRequest, ArticleLoadReq request)
|
|
|
+ {
|
|
|
+ var url = httpRequest.Path;
|
|
|
+ var json = JsonConvert.SerializeObject(request);
|
|
|
+ log.Debug("URL: " + url + " => Request: " + json);
|
|
|
+ try
|
|
|
+ {
|
|
|
+ string lang = (request.lang ?? "lo").ToLower();
|
|
|
+ int pageNumber = request.pageNumber < 0 ? 0 : request.pageNumber;
|
|
|
+ int pageSize = request.pageSize <= 0 ? 10 : request.pageSize;
|
|
|
+
|
|
|
+ // If slug is provided, return single article detail
|
|
|
+ if (!string.IsNullOrEmpty(request.slug))
|
|
|
+ {
|
|
|
+ var article = dbContext.Articles
|
|
|
+ .Where(a => a.Slug == request.slug && a.Status == true)
|
|
|
+ .Select(a => new
|
|
|
+ {
|
|
|
+ a.Id,
|
|
|
+ title = lang == "en"
|
|
|
+ ? (a.TitleEn ?? a.Title)
|
|
|
+ : (a.TitleLo ?? a.Title),
|
|
|
+ a.Slug,
|
|
|
+ summary = lang == "en"
|
|
|
+ ? (a.SummaryEn ?? a.Summary)
|
|
|
+ : (a.SummaryLo ?? a.Summary),
|
|
|
+ content = lang == "en"
|
|
|
+ ? (a.ContentEn ?? a.Content)
|
|
|
+ : (a.ContentLo ?? a.Content),
|
|
|
+ a.ThumbnailUrl,
|
|
|
+ a.CoverImageUrl,
|
|
|
+ metaDescription = lang == "en"
|
|
|
+ ? (a.MetaDescriptionEn ?? a.MetaDescription)
|
|
|
+ : (a.MetaDescriptionLo ?? a.MetaDescription),
|
|
|
+ a.MetaKeywords,
|
|
|
+ a.CategoryId,
|
|
|
+ a.ViewCount,
|
|
|
+ a.IsFeatured,
|
|
|
+ a.PublishedDate,
|
|
|
+ a.CreatedDate
|
|
|
+ })
|
|
|
+ .FirstOrDefault();
|
|
|
+
|
|
|
+ if (article == null)
|
|
|
+ {
|
|
|
+ return DotnetLib.Http.HttpResponse.BuildResponse(
|
|
|
+ log,
|
|
|
+ url,
|
|
|
+ json,
|
|
|
+ CommonErrorCode.Error,
|
|
|
+ ConfigManager.Instance.GetConfigWebValue("ARTICLE_NOT_FOUND", lang),
|
|
|
+ new { }
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // Increment view count
|
|
|
+ var articleEntity = dbContext.Articles.FirstOrDefault(a => a.Slug == request.slug);
|
|
|
+ if (articleEntity != null)
|
|
|
+ {
|
|
|
+ articleEntity.ViewCount = (articleEntity.ViewCount ?? 0) + 1;
|
|
|
+ await dbContext.SaveChangesAsync();
|
|
|
+ }
|
|
|
+
|
|
|
+ return DotnetLib.Http.HttpResponse.BuildResponse(
|
|
|
+ log,
|
|
|
+ url,
|
|
|
+ json,
|
|
|
+ CommonErrorCode.Success,
|
|
|
+ ConfigManager.Instance.GetConfigWebValue("LOAD_SUCCESS", lang),
|
|
|
+ new { article }
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // Query articles list
|
|
|
+ var query = dbContext.Articles
|
|
|
+ .Where(a => a.Status == true);
|
|
|
+
|
|
|
+ // Filter by category
|
|
|
+ if (request.categoryId.HasValue)
|
|
|
+ {
|
|
|
+ query = query.Where(a => a.CategoryId == request.categoryId);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Filter by featured
|
|
|
+ if (request.isFeatured.HasValue && request.isFeatured.Value)
|
|
|
+ {
|
|
|
+ query = query.Where(a => a.IsFeatured == true);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Get total count for pagination
|
|
|
+ int totalCount = query.Count();
|
|
|
+ int totalPages = (int)Math.Ceiling((double)totalCount / pageSize);
|
|
|
+
|
|
|
+ // Apply pagination and ordering (pinned first, then by published date)
|
|
|
+ var articles = query
|
|
|
+ .OrderByDescending(a => a.IsPinned)
|
|
|
+ .ThenByDescending(a => a.PublishedDate)
|
|
|
+ .ThenByDescending(a => a.CreatedDate)
|
|
|
+ .Skip(pageNumber * pageSize)
|
|
|
+ .Take(pageSize)
|
|
|
+ .Select(a => new
|
|
|
+ {
|
|
|
+ a.Id,
|
|
|
+ title = lang == "en"
|
|
|
+ ? (a.TitleEn ?? a.Title)
|
|
|
+ : (a.TitleLo ?? a.Title),
|
|
|
+ a.Slug,
|
|
|
+ summary = lang == "en"
|
|
|
+ ? (a.SummaryEn ?? a.Summary)
|
|
|
+ : (a.SummaryLo ?? a.Summary),
|
|
|
+ a.ThumbnailUrl,
|
|
|
+ a.CategoryId,
|
|
|
+ a.ViewCount,
|
|
|
+ a.IsFeatured,
|
|
|
+ a.IsPinned,
|
|
|
+ a.PublishedDate
|
|
|
+ })
|
|
|
+ .ToList();
|
|
|
+
|
|
|
+ return DotnetLib.Http.HttpResponse.BuildResponse(
|
|
|
+ log,
|
|
|
+ url,
|
|
|
+ json,
|
|
|
+ CommonErrorCode.Success,
|
|
|
+ ConfigManager.Instance.GetConfigWebValue("LOAD_SUCCESS", lang),
|
|
|
+ new
|
|
|
+ {
|
|
|
+ items = articles,
|
|
|
+ pagination = new
|
|
|
+ {
|
|
|
+ pageNumber,
|
|
|
+ pageSize,
|
|
|
+ totalCount,
|
|
|
+ totalPages
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ }
|
|
|
+ catch (Exception exception)
|
|
|
+ {
|
|
|
+ log.Error("Exception: ", exception);
|
|
|
+ }
|
|
|
+ return DotnetLib.Http.HttpResponse.BuildResponse(
|
|
|
+ log,
|
|
|
+ url,
|
|
|
+ json,
|
|
|
+ CommonErrorCode.SystemError,
|
|
|
+ ConfigManager.Instance.GetConfigWebValue("SYSTEM_FAILURE"),
|
|
|
+ new { }
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+}
|