diff --git a/Library.Encyclopedia.API/Controllers/EncylopediaController.cs b/Library.Encyclopedia.API/Controllers/EncylopediaController.cs index 8d264b4..70a47ba 100644 --- a/Library.Encyclopedia.API/Controllers/EncylopediaController.cs +++ b/Library.Encyclopedia.API/Controllers/EncylopediaController.cs @@ -6,6 +6,7 @@ using Library.Encyclopedia.Entity.Models.External; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -28,10 +29,10 @@ public class EncylopediaController : ControllerBase /// /// /// - public EncylopediaController(ILogger logger, IApplicationDbContext dbContext) + public EncylopediaController(ILogger logger, IApplicationDbContext dbContext, IConfiguration configuration) { _logger = logger; - this.mainDataAccess = new MainDataAccess(dbContext); + this.mainDataAccess = new MainDataAccess(dbContext, configuration); } /// @@ -39,18 +40,19 @@ public EncylopediaController(ILogger logger, IApplication /// /// /// - /// + /// /// /// [HttpGet] public async Task Get(string query, int offset = 0, - int size = 10, + int limit = 10, + int previewSize = 50, bool asc = true) { try { - var response = await mainDataAccess.GetAsync(query, offset, size, asc); + var response = await mainDataAccess.GetAsync(query, offset, limit, previewSize, asc); if (response == null) { return StatusCode(204); @@ -72,18 +74,18 @@ public async Task Get(string query, /// /// /// - /// + /// /// /// [HttpGet("category")] public async Task GetByCategory(string category, int offset = 0, - int size = 10, + int limit = 10, bool asc = true) { try { - var response = await mainDataAccess.GetByCategoryAsync(category, offset, size, asc); + var response = await mainDataAccess.GetByCategoryAsync(category, offset, limit, asc); if (response == null) { @@ -106,18 +108,18 @@ public async Task GetByCategory(string category, /// /// /// - /// + /// /// /// [HttpGet("alphabet")] public async Task GetByStartingAlphabet(char alphabet, int offset = 0, - int size = 10, + int limit = 10, bool asc = true) { try { - var response = await mainDataAccess.GetByAlphabetAsync(alphabet, offset, size, asc); + var response = await mainDataAccess.GetByAlphabetAsync(alphabet, offset, limit, asc); if (response == null) { diff --git a/Library.Encyclopedia.API/appsettings.json b/Library.Encyclopedia.API/appsettings.json index 8d02394..7b695ce 100644 --- a/Library.Encyclopedia.API/appsettings.json +++ b/Library.Encyclopedia.API/appsettings.json @@ -6,6 +6,7 @@ "Microsoft.Hosting.Lifetime": "Information" } }, + "App-Base-Url": "http://localhost:4200", "AllowedHosts": "*", "ConnectionStrings": { "DefaultConnection": "Server=localhost;Database=Encyclopedia;User=root;Password=root" diff --git a/Library.Encyclopedia.DataAccess/DataAccess/MainDataAccess.cs b/Library.Encyclopedia.DataAccess/DataAccess/MainDataAccess.cs index 3374177..dba1a0b 100644 --- a/Library.Encyclopedia.DataAccess/DataAccess/MainDataAccess.cs +++ b/Library.Encyclopedia.DataAccess/DataAccess/MainDataAccess.cs @@ -3,6 +3,7 @@ using Library.Encyclopedia.Entity.Models; using Library.Encyclopedia.Entity.Models.External; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.IO; @@ -10,41 +11,48 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; +using System.Web; namespace Library.Encyclopedia.DataAccess.DataAccess { public class MainDataAccess : IMainDataAccess { private IApplicationDbContext _dbcontext; - public MainDataAccess(IApplicationDbContext dbcontext) + private string APP_BASE_URL; + + public MainDataAccess(IApplicationDbContext dbcontext, IConfiguration configuration) { + APP_BASE_URL = configuration.GetSection("App-Base-Url").Value; _dbcontext = dbcontext; } #region GET - async Task IMainDataAccess.GetAsync(string query, int offset, int pagesize, bool ascending) + async Task IMainDataAccess.GetAsync(string query, int offset, int pagesize, int previewSize, bool ascending) { - query = query.ToLower(); - var temp = _dbcontext.Main.Where(s => s.Description.ToLower().Contains(query) || s.Title.ToLower().Contains(query)) + // random cleanup + //await CleanUpData(); + + query = query != null ? query.ToLower() : string.Empty; + var temp = _dbcontext.Main.Where(s => s.RawDescription.ToLower().Contains(query) || s.Title.ToLower().Contains(query)) .Skip(offset) - .Take(pagesize); + .Take(pagesize) + .Include(s => s.Links); IEnumerable
data; if (ascending) data = await temp.OrderBy(s => s.Title) - .ThenBy(s => s.Description) + .ThenBy(s => s.RawDescription) .ToListAsync(); else data = await temp.OrderByDescending(s => s.Title) - .ThenByDescending(s => s.Description) + .ThenByDescending(s => s.RawDescription) .ToListAsync(); - var total = await _dbcontext.Main.CountAsync(s => s.Description.ToLower().Contains(query) || s.Title.ToLower().Contains(query)); + var total = await _dbcontext.Main.CountAsync(s => s.RawDescription.ToLower().Contains(query) || s.Title.ToLower().Contains(query)); + + MainMinimizedExternalCollection result = new MainMinimizedExternalCollection(data.MinimizeWithQuery(query, previewSize), total); - MainMinimizedExternalCollection result = new MainMinimizedExternalCollection(data.Minimize(), total); - // random cleanup - await CleanUpData(); return result; } @@ -60,10 +68,10 @@ async Task IMainDataAccess.GetByCategoryAsync(s IEnumerable
data; if (ascending) data = temp.OrderBy(s => s.Title) - .ThenBy(s => s.Description); + .ThenBy(s => s.RawDescription); else data = temp.OrderByDescending(s => s.Title) - .ThenByDescending(s => s.Description); + .ThenByDescending(s => s.RawDescription); var total = rawData.Count(s => s.Category.ToLower().Split(',', StringSplitOptions.None).Contains(category)); @@ -82,11 +90,11 @@ async Task IMainDataAccess.GetByAlphabetAsync(c IEnumerable
data; if (ascending) data = await temp.OrderBy(s => s.Title) - .ThenBy(s => s.Description) + .ThenBy(s => s.RawDescription) .ToListAsync(); else data = await temp.OrderByDescending(s => s.Title) - .ThenByDescending(s => s.Description) + .ThenByDescending(s => s.RawDescription) .ToListAsync(); var total = await _dbcontext.Main.CountAsync(s => s.Title.ToLower().StartsWith(alph)); @@ -98,7 +106,20 @@ async Task IMainDataAccess.GetByAlphabetAsync(c async Task
IMainDataAccess.GetAsync(Guid id) { - return await _dbcontext.Main.Include(s => s.Files).Include(s => s.Links).FirstOrDefaultAsync(s => s.Id == id); + Main item = await _dbcontext.Main.Include(s => s.Files).Include(s => s.Links).FirstOrDefaultAsync(s => s.Id == id); + + // replace links in item + while (item.RichDescription.IndexOf("$$$") != -1) + { + var startIndex = item.RichDescription.IndexOf("$$$") + 3; + var endIndex = item.RichDescription.Substring(startIndex).IndexOf("$$$"); + + var referenceid = item.RichDescription.Substring(startIndex, endIndex); + + item.RichDescription= item.RichDescription.Replace($"$$${referenceid}$$$", $"{item.Links.FirstOrDefault(s => s.ReferenceId.ToString() == referenceid).Description}"); + } + + return item; } #endregion @@ -124,7 +145,10 @@ public async Task UpdateAsync(Guid id, MainUpdateModel model) if (entry != null) { entry.Title = model.Title; - entry.Description = model.Description; + entry.RichDescription = model.RichDescription; + + // TODO : do conversion on raw description + entry.Category = model.Category; _dbcontext.Main.Update(entry); @@ -172,19 +196,18 @@ public async Task CleanUpData() { string searchStartString = ""; - var links = new List(); + var allLinks = new List(); var allData = await _dbcontext.Main.ToListAsync(); - //using StreamWriter file = new StreamWriter(@"C:\temp\temp.txt", append: true); foreach (var item in allData) { - if (item.Description != null) + if (item.RichDescription != null) { // Extract start indices List startIndexes = new List(); for (int index = 0; ; index += searchStartString.Length) { - index = item.Description.IndexOf(searchStartString, index); + index = item.RichDescription.IndexOf(searchStartString, index); if (index != -1) startIndexes.Add(index); else break; @@ -194,32 +217,32 @@ public async Task CleanUpData() List endIndexes = new List(); for (int index = 0; ; index += searchEndString.Length) { - index = item.Description.IndexOf(searchEndString, index); + index = item.RichDescription.IndexOf(searchEndString, index); if (index != -1) endIndexes.Add(index); else break; } // - var newDesc = new string(item.Description); + var newDesc = new string(item.RichDescription); + var links = new List(); + for (int i = 0; i < startIndexes.Count; i++) { - string value = item.Description.Substring(startIndexes[i], endIndexes[i] - startIndexes[i] + searchEndString.Length); + string value = item.RichDescription.Substring(startIndexes[i], endIndexes[i] - startIndexes[i] + searchEndString.Length); if (value.Contains("http://")) { var id = value.Substring(value.IndexOf("id=") + 3, 36); var desc = value.Substring(value.IndexOf(">") + 1, value.IndexOf("<", value.IndexOf(">")) - value.IndexOf(">") - 1); - //await file.WriteLineAsync($"id = {id} | Description = {desc}"); - newDesc = newDesc.Replace(value, $"$$${id}$$$"); - //await file.WriteLineAsync($"new description = {newDesc}"); // add to links list links.Add(new Links { Id = Guid.NewGuid(), - MainId = Guid.Parse(id), + MainId = item.Id, + ReferenceId = Guid.Parse(id), Link = value, Description = desc, IsInternal = true @@ -228,18 +251,54 @@ public async Task CleanUpData() } // update the description - item.Description = newDesc; + item.RichDescription = newDesc; + // update the links array + item.Links = links; + allLinks.AddRange(links); } } // add to the links table - await _dbcontext.Links.AddRangeAsync(links); - + await _dbcontext.Links.AddRangeAsync(allLinks); // update the main data _dbcontext.Main.UpdateRange(allData); + await _dbcontext.SaveChanges(); + allData = await _dbcontext.Main.Include(s => s.Links).ToListAsync(); + + foreach (var item in allData) + { + var temp = new string(item.RichDescription); + + if (!string.IsNullOrEmpty(temp)) + { + // replace the links + if (item.Links != null && item.Links.Any()) + { + foreach (var link in item.Links) + { + var identifier = $"$$${link.ReferenceId}$$$"; + temp = temp.Replace(identifier, link.Description); + } + } + + item.RawDescription = temp; + + // replace the HTML tags + item.RawDescription = StripHTML(item.RawDescription, true); + } + } + // update the main data + _dbcontext.Main.UpdateRange(allData); await _dbcontext.SaveChanges(); } + + public static string StripHTML(string HTMLText, bool decode = true) + { + Regex reg = new Regex("<[^>]+>", RegexOptions.IgnoreCase); + var stripped = reg.Replace(HTMLText, ""); + return decode ? HttpUtility.HtmlDecode(stripped) : stripped; + } #endregion } } \ No newline at end of file diff --git a/Library.Encyclopedia.Entity/Interfaces/IMainDataAccess.cs b/Library.Encyclopedia.Entity/Interfaces/IMainDataAccess.cs index cc8c6eb..e50686d 100644 --- a/Library.Encyclopedia.Entity/Interfaces/IMainDataAccess.cs +++ b/Library.Encyclopedia.Entity/Interfaces/IMainDataAccess.cs @@ -9,7 +9,7 @@ namespace Library.Encyclopedia.Entity.Interfaces public interface IMainDataAccess { #region GET - public Task GetAsync(string query, int offset, int pagesize, bool ascending); + public Task GetAsync(string query, int offset, int pagesize, int previewSize, bool ascending); public Task GetByCategoryAsync(string category, int offset, int pagesize, bool ascending); public Task GetByAlphabetAsync(char startingAlphabet, int offset, int pagesize, bool ascending); public Task
GetAsync(Guid id); diff --git a/Library.Encyclopedia.Entity/Models/External/MainMinimizedExternal.cs b/Library.Encyclopedia.Entity/Models/External/MainMinimizedExternal.cs index 7aca354..df21a9e 100644 --- a/Library.Encyclopedia.Entity/Models/External/MainMinimizedExternal.cs +++ b/Library.Encyclopedia.Entity/Models/External/MainMinimizedExternal.cs @@ -8,8 +8,7 @@ public class MainMinimizedExternal { public Guid Id { get; set; } public string Title { get; set; } - public string Description { get; set; } - public string Category { get; set; } + public string Preview { get; set; } } public class MainMinimizedExternalCollection : QueryExternalModel { diff --git a/Library.Encyclopedia.Entity/Models/External/MainUpdateModel.cs b/Library.Encyclopedia.Entity/Models/External/MainUpdateModel.cs index 225404b..90bbab1 100644 --- a/Library.Encyclopedia.Entity/Models/External/MainUpdateModel.cs +++ b/Library.Encyclopedia.Entity/Models/External/MainUpdateModel.cs @@ -3,7 +3,8 @@ public class MainUpdateModel { public string Title { get; set; } - public string Description { get; set; } + public string RawDescription { get; set; } + public string RichDescription { get; set; } public string Category { get; set; } } } \ No newline at end of file diff --git a/Library.Encyclopedia.Entity/Models/Links.cs b/Library.Encyclopedia.Entity/Models/Links.cs index 0d2eb11..d75f55d 100644 --- a/Library.Encyclopedia.Entity/Models/Links.cs +++ b/Library.Encyclopedia.Entity/Models/Links.cs @@ -10,6 +10,8 @@ public class Links [Required] public Guid MainId { get; set; } [Required] + public Guid ReferenceId { get; set; } + [Required] public string Link { get; set; } public string Description { get; set; } [Required] diff --git a/Library.Encyclopedia.Entity/Models/Main.cs b/Library.Encyclopedia.Entity/Models/Main.cs index bc6bf11..9109bca 100644 --- a/Library.Encyclopedia.Entity/Models/Main.cs +++ b/Library.Encyclopedia.Entity/Models/Main.cs @@ -12,7 +12,9 @@ public class Main [Required] [StringLength(1024)] public string Title { get; set; } - public string Description { get; set; } + public string RichDescription { get; set; } + public string RawDescription { get; set; } + [StringLength(256)] public string Category { get; set; } @@ -22,15 +24,73 @@ public class Main public static class MainExtensions { + public static MainMinimizedExternal MinimizeWithQuery(this Main main, string query, int previewText_maxlength) + { + if (!string.IsNullOrEmpty(query)) + { + int indexOfQuery = main.RawDescription.IndexOf(query, StringComparison.OrdinalIgnoreCase); + + // find the complete word + if (indexOfQuery != -1) + { + for (int i = indexOfQuery; i >= 0; i--) + { + if (char.IsSeparator(main.RawDescription[i])) + { + indexOfQuery = i; + break; + } + } + } + + int lengthOfPreviewText = indexOfQuery == -1 + ? Math.Min(previewText_maxlength, main.RawDescription.Length) + : Math.Min(previewText_maxlength, main.RawDescription.Length - indexOfQuery); + + return new MainMinimizedExternal + { + Id = main.Id, + Preview = indexOfQuery == -1 + ? main.RawDescription.Length > previewText_maxlength + ? main.RawDescription.Substring(0, lengthOfPreviewText) + " ..." + : main.RawDescription.Substring(0, lengthOfPreviewText) + : main.RawDescription.Length - indexOfQuery > previewText_maxlength + ? " ... " + main.RawDescription.Substring(indexOfQuery, lengthOfPreviewText) + " ..." + : main.RawDescription.Length > previewText_maxlength + ? " ... " + main.RawDescription.Substring(main.RawDescription.Length - previewText_maxlength, previewText_maxlength) + : main.RawDescription, + Title = main.Title + }; + } + else + { + int lengthOfPreviewText = Math.Min(previewText_maxlength, main.RawDescription.Length); + return new MainMinimizedExternal + { + Id = main.Id, + Preview = main.RawDescription.Length > previewText_maxlength + ? main.RawDescription.Substring(0, lengthOfPreviewText) + " ..." + : main.RawDescription.Substring(0, lengthOfPreviewText), + Title = main.Title + }; + } + } public static MainMinimizedExternal Minimize(this Main main) { - return new MainMinimizedExternal { + return new MainMinimizedExternal + { Id = main.Id, - Category = main.Category, - Description = main.Description, + Preview = main.RawDescription, Title = main.Title }; } + public static IEnumerable MinimizeWithQuery(this IEnumerable
collection, string query, int previewText_maxlength) + { + foreach (var item in collection) + { + yield return MinimizeWithQuery(item, query, previewText_maxlength); + } + } public static IEnumerable Minimize(this IEnumerable
collection) { foreach (var item in collection)