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).Include(s => s.Files).FirstOrDefaultAsync(s => s.Id == id);
+
+ if (item != null)
+ {
+ if (item.RichDescription != null)
+ {
+ // 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;
+ }
+
+ return item;
}
#endregion
#region CREATE
public async Task CreateAsync(Main model)
{
+ if (model.RichDescription.Contains("$$$"))
+ throw new CreateFailedException(CreateFailErrorCode.INVALID_INPUT_SEQUENCE);
+
// assign a random id
model.Id = Guid.NewGuid();
+ model.Category = model.Category == string.Empty ? null : model.Category;
+
+ model = ReplaceInternalLinks(model);
+ model = ReplaceLineBreaks(model);
+ //santize data
+ model.RawDescription = StripHTML(model.RawDescription);
await _dbcontext.Main.AddAsync(model);
+ await _dbcontext.Links.AddRangeAsync(model.Links);
+
await _dbcontext.SaveChanges();
return model.Id;
}
+
+ private Main ReplaceLineBreaks(Main model)
+ {
+ string searchStartString = " startIndexes = new List();
+ for (int index = 0; ; index += searchStartString.Length)
+ {
+ index = model.RichDescription.IndexOf(searchStartString, index);
+ if (index != -1)
+ startIndexes.Add(index);
+ else break;
+ }
+
+ // Extract end indices
+ List endIndexes = new List();
+ for (int index = 0; ; index += searchEndString.Length)
+ {
+ index = model.RichDescription.IndexOf(searchEndString, index);
+ if (index != -1)
+ endIndexes.Add(index);
+ else break;
+ }
+
+ var newDesc = new string(model.RichDescription);
+
+ for (int i = 0; i < startIndexes.Count; i++)
+ {
+ string tag = model.RichDescription.Substring(startIndexes[i], endIndexes[i] - startIndexes[i] + searchEndString.Length);
+
+ string value = model.RichDescription.Substring(startIndexes[i] + searchStartString.Length, endIndexes[i] - startIndexes[i] - +searchStartString.Length);
+ value = value.Substring(value.IndexOf('>') + 1);
+
+ if (string.IsNullOrEmpty(value) || string.IsNullOrWhiteSpace(value))
+ {
+ newDesc = newDesc.Replace(tag, "
");
+ }
+ }
+
+ model.RichDescription = newDesc;
+ }
+
+ return model;
+ }
+
+ private Main ReplaceInternalLinks(Main model, bool isUpdate = false)
+ {
+ string searchStartString = "";
+ model.Links ??= new List();
+ var newCreatedLinks = new List();
+ var updatedLinks = new List();
+
+ if (model.RichDescription != null)
+ {
+ // Extract start indices
+ List startIndexes = new List();
+ for (int index = 0; ; index += searchStartString.Length)
+ {
+ index = model.RichDescription.IndexOf(searchStartString, index);
+ if (index != -1)
+ startIndexes.Add(index);
+ else break;
+ }
+
+ // Extract end indices
+ List endIndexes = new List();
+ for (int index = 0; ; index += searchEndString.Length)
+ {
+ index = model.RichDescription.IndexOf(searchEndString, index);
+ if (index != -1)
+ endIndexes.Add(index);
+ else break;
+ }
+
+ var newDesc = new string(model.RichDescription);
+ var newDesc2 = new string(model.RichDescription);
+
+ for (int i = 0; i < startIndexes.Count; i++)
+ {
+ string value = model.RichDescription.Substring(startIndexes[i], endIndexes[i] - startIndexes[i] + searchEndString.Length);
+ if (value.Contains(APP_BASE_URL))
+ {
+ var id = value.Substring(value.IndexOf(APP_BASE_URL) + APP_BASE_URL.Length + 1, 36);
+ var desc = value.Substring(value.IndexOf(">") + 1, value.IndexOf("<", value.IndexOf(">")) - value.IndexOf(">") - 1);
+
+ newDesc = newDesc.Replace(value, $"$$${id}$$$");
+ newDesc2 = newDesc2.Replace(value, desc);
+
+ if (!model.Links.Any(s => s.ReferenceId == Guid.Parse(id)))
+ {
+ // add to links list
+ Links item = new Links
+ {
+ Id = Guid.NewGuid(),
+ MainId = model.Id,
+ ReferenceId = Guid.Parse(id),
+ Link = value,
+ Description = desc,
+ IsInternal = true
+ };
+ model.Links.Add(item);
+
+ newCreatedLinks.Add(item);
+ }
+ else
+ {
+ model.Links.FirstOrDefault(s => s.ReferenceId == Guid.Parse(id)).Link = value;
+ model.Links.FirstOrDefault(s => s.ReferenceId == Guid.Parse(id)).Description = desc;
+ updatedLinks.Add(model.Links.FirstOrDefault(s => s.ReferenceId == Guid.Parse(id)));
+ }
+
+ }
+ }
+
+ model.RichDescription = newDesc;
+ model.RawDescription = newDesc2;
+
+ if (isUpdate)
+ {
+ _dbcontext.Links.AddRangeAsync(newCreatedLinks);
+ _dbcontext.Links.UpdateRange(updatedLinks);
+ _dbcontext.SaveChanges().Wait();
+ }
+
+ }
+
+ return model;
+ }
#endregion
#region UPDATE
- public async Task UpdateAsync(Guid id, MainUpdateModel model)
+ public async Task UpdateAsync(Guid id, MainUpdateModel model)
{
// find the entry
- var entry = await _dbcontext.Main.FirstOrDefaultAsync(s => s.Id == id);
+ var entry = await _dbcontext.Main.Include(s => s.Links).Include(s => s.Files).FirstOrDefaultAsync(s => s.Id == id);
if (entry != null)
{
- entry.Title = model.Title;
- entry.Description = model.Description;
- entry.Category = model.Category;
+ if (model != null)
+ {
+ entry.Title = model.Title ?? entry.Title;
- _dbcontext.Main.Update(entry);
- await _dbcontext.SaveChanges();
+ if (model.RichDescription != null)
+ {
+ if (model.RichDescription != null && model.RichDescription.Contains("$$$"))
+ throw new UpdateFailedException(UpdateFailErrorCode.INVALID_INPUT_SEQUENCE);
+
+ entry.RichDescription = model.RichDescription;
+
+ entry = ReplaceInternalLinks(entry, true);
+ entry = ReplaceLineBreaks(entry);
+
+ //santize data
+ entry.RawDescription = StripHTML(entry.RawDescription);
+ }
+
+ entry.Category = model.Category == null ? entry.Category : model.Category == string.Empty ? null : model.Category;
+
+ _dbcontext.Main.Update(entry);
+ await _dbcontext.SaveChanges();
+
+ if (entry.RichDescription != null)
+ {
+ // replace links in item
+ while (entry.RichDescription.IndexOf("$$$") != -1)
+ {
+ var startIndex = entry.RichDescription.IndexOf("$$$") + 3;
+ var endIndex = entry.RichDescription.Substring(startIndex).IndexOf("$$$");
+
+ var referenceid = entry.RichDescription.Substring(startIndex, endIndex);
+
+ entry.RichDescription = entry.RichDescription.Replace($"$$${referenceid}$$$", $"{entry.Links.FirstOrDefault(s => s.ReferenceId.ToString() == referenceid).Description}");
+ }
+ }
+
+ return entry;
+ }
}
else
throw new UpdateFailedException(UpdateFailErrorCode.EntryNotFound);
+
+ return null;
}
#endregion
@@ -139,11 +419,24 @@ public async Task UpdateAsync(Guid id, MainUpdateModel model)
public async Task DeleteAsync(Guid id)
{
// find the entry
- var entry = await _dbcontext.Main.FirstOrDefaultAsync(s => s.Id == id);
+ var entry = await _dbcontext.Main.Include(s => s.Links).Include(s => s.Files).FirstOrDefaultAsync(s => s.Id == id);
if (entry != null)
{
+ if (entry.Links != null && entry.Links.Any()) _dbcontext.Links.RemoveRange(entry.Links);
+ if (entry.Files != null && entry.Files.Any())
+ {
+ _dbcontext.Files.RemoveRange(entry.Files);
+ this.filesAdapter.DeleteFiles(entry.Id.ToString());
+ }
_dbcontext.Main.Remove(entry);
+
+ // delete all comments and likes
+ var allComments = await _dbcontext.Comments.Where(s => s.MainId == entry.Id).ToListAsync();
+ _dbcontext.Comments.RemoveRange(allComments);
+ var allCommentIds = allComments.Select(s => s.Id);
+ _dbcontext.Likes.RemoveRange(await _dbcontext.Likes.Where(s => allCommentIds.Contains(s.CommentId)).ToListAsync());
+
await _dbcontext.SaveChanges();
}
else
@@ -158,8 +451,13 @@ public async Task> GetAllCategoriesAsync()
var result = new List();
data.ForEach(item =>
{
- result.AddRange(item.Split(','));
+ if (!string.IsNullOrEmpty(item))
+ {
+ result.AddRange(item.Split(','));
+ }
});
+
+ result.RemoveAll(s => s == string.Empty);
return result.Distinct();
}
@@ -172,19 +470,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 +491,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 +525,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.DataAccess/Email/EmailAdapter.cs b/Library.Encyclopedia.DataAccess/Email/EmailAdapter.cs
new file mode 100644
index 0000000..8378950
--- /dev/null
+++ b/Library.Encyclopedia.DataAccess/Email/EmailAdapter.cs
@@ -0,0 +1,52 @@
+using Library.Encyclopedia.Entity.Models;
+using Microsoft.Extensions.Configuration;
+using SendGrid;
+using SendGrid.Helpers.Mail;
+using System;
+using System.Collections.Generic;
+using System.DirectoryServices.AccountManagement;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Library.Encyclopedia.DataAccess.Email
+{
+ public class EmailAdapter
+ {
+ private readonly IConfiguration configuration;
+
+ public EmailAdapter(IConfiguration configuration)
+ {
+ this.configuration = configuration;
+ }
+
+ public async Task SendEmail(string userName, string email, string content)
+ {
+ var apiKey = configuration.GetSection("SendGrid-APIKEY").Value;
+ var client = new SendGridClient(apiKey);
+ var from = new EmailAddress(configuration.GetSection("Admin-Email").Value, configuration.GetSection("Admin-Username").Value);
+
+ var to = new List();
+
+ using (var context = new PrincipalContext(ContextType.Machine))
+ {
+ using (var group = GroupPrincipal.FindByIdentity(context, configuration.GetSection("PFW-EmailList-Group").Value))
+ {
+ if (group != null)
+ {
+ var members = group.GetMembers(true);
+ foreach (UserPrincipal user in members)
+ {
+ to.Add(new EmailAddress { Email = user.EmailAddress, Name = user.DisplayName });
+ }
+ }
+ }
+ }
+
+ var msg = MailHelper.CreateSingleTemplateEmailToMultipleRecipients(from, to, configuration.GetSection("Template-Id").Value, new EmailPropertiesV1 { Content = content, Name = userName, Email = email });
+ var response = await client.SendEmailAsync(msg);
+
+ if (!response.IsSuccessStatusCode)
+ throw new Exception("Email not sent!");
+ }
+ }
+}
diff --git a/Library.Encyclopedia.DataAccess/FileAccess/FTPAdapter.cs b/Library.Encyclopedia.DataAccess/FileAccess/FTPAdapter.cs
deleted file mode 100644
index 1e1cae2..0000000
--- a/Library.Encyclopedia.DataAccess/FileAccess/FTPAdapter.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using Library.Encyclopedia.Entity.Interfaces;
-using Library.Encyclopedia.Entity.Models;
-using Microsoft.AspNetCore.Http;
-using Renci.SshNet;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Net;
-using System.Text;
-
-namespace Library.Encyclopedia.DataAccess.FileAccess
-{
- public class FTPAdapter : IFilesAdapter
- {
- private readonly string url;
- private readonly NetworkCredential networkCredential;
-
- public FTPAdapter(string url, NetworkCredential networkCredential)
- {
- this.url = url;
- this.networkCredential = networkCredential;
- }
-
- public IEnumerable DownloadFiles(IEnumerable files, string directory)
- {
- List responses = new List();
- var customUrl = $@"/home/{networkCredential.UserName}";
-
- using (SftpClient client = new SftpClient(url, 22, networkCredential.UserName, networkCredential.Password))
- {
- client.Connect();
- foreach (var file in files)
- {
- using (var stream = File.OpenWrite(Path.Combine(directory, file.FileName)))
- {
- client.DownloadFile(customUrl + file.FilePath, stream);
- responses.Add(true);
- }
- }
- }
-
- return responses;
- }
-
- public IEnumerable UploadFiles(Guid id, List files)
- {
- List responses = new List();
- var customUrl = $@"/home/{networkCredential.UserName}/encyclopedia-media/{id}/";
-
- using (SftpClient client = new SftpClient(url, 22, networkCredential.UserName, networkCredential.Password))
- {
- client.Connect();
- if (!client.Exists(customUrl))
- client.CreateDirectory(customUrl);
-
- foreach (var file in files)
- {
- if (client.Exists(customUrl + file.FileName))
- client.DeleteFile(customUrl + file.FileName);
-
- client.UploadFile(file.OpenReadStream(), customUrl + file.FileName);
- responses.Add(true);
- }
- }
-
- return responses;
- }
- }
-}
diff --git a/Library.Encyclopedia.DataAccess/FileAccess/LinuxFileSaveAdapter.cs b/Library.Encyclopedia.DataAccess/FileAccess/LinuxFileSaveAdapter.cs
new file mode 100644
index 0000000..7eddfd7
--- /dev/null
+++ b/Library.Encyclopedia.DataAccess/FileAccess/LinuxFileSaveAdapter.cs
@@ -0,0 +1,105 @@
+using Library.Encyclopedia.Entity.Interfaces;
+using Microsoft.AspNetCore.Http;
+using Renci.SshNet;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Library.Encyclopedia.DataAccess.FileAccess
+{
+ public class LinuxFileSaveAdapter : IFilesAdapter, IDisposable
+ {
+ private readonly string url;
+ private readonly string basePath;
+ private readonly string tempAssetsFilePath;
+ private readonly NetworkCredential networkCredential;
+ private SftpClient client;
+
+ public LinuxFileSaveAdapter(string url, string userName, string password, string basePath, string tempAssetsFilePath)
+ {
+ this.url = url;
+ this.basePath = basePath;
+ this.tempAssetsFilePath = tempAssetsFilePath;
+ this.networkCredential = new NetworkCredential(userName, password);
+
+ client = new SftpClient(url, 22, networkCredential.UserName, networkCredential.Password);
+ client.Connect();
+ }
+
+ public void CreateViewableLink(string id, string name)
+ {
+ if (!Directory.Exists(Path.Combine(tempAssetsFilePath, id)))
+ Directory.CreateDirectory(Path.Combine(tempAssetsFilePath, id));
+
+ var remotePath = $@"/home/{networkCredential.UserName}/" + basePath + '/' + id.ToString() + '/' + name;
+ using (Stream fileStream = File.Create(Path.Combine(tempAssetsFilePath, id, name)))
+ {
+ client.DownloadFile(remotePath, fileStream);
+ }
+ }
+
+ public void DeleteFile(string id, string name)
+ {
+ var completeUrl = $@"/home/{networkCredential.UserName}/" + basePath + '/' + id.ToString() + '/' + name;
+
+
+ if (client.Exists(completeUrl))
+ client.DeleteFile(completeUrl);
+ }
+
+ public void DeleteFiles(string id)
+ {
+ var completeUrl = $@"/home/{networkCredential.UserName}/" + basePath + '/' + id.ToString();
+
+ if (client.Exists(completeUrl))
+ {
+ IEnumerable files = client.ListDirectory(completeUrl);
+ foreach (var file in files)
+ {
+ if (file.Name != "." && file.Name != "..")
+ {
+ client.DeleteFile(file.FullName);
+ }
+ }
+
+ client.DeleteDirectory(completeUrl);
+ }
+ }
+
+ public void DestroyViewableLink(string id, string name)
+ {
+ File.Delete(Path.Combine(tempAssetsFilePath, id, name));
+ }
+
+ public void Dispose()
+ {
+ this.client.Disconnect();
+ this.client.Dispose();
+ }
+
+ public Stream DownloadFile(string id, string name)
+ {
+ var completeUrl = $@"/home/{networkCredential.UserName}/" + basePath + '/' + id.ToString() + '/' + name;
+ return client.OpenRead(completeUrl);
+ }
+
+ public Task UploadFile(Guid id, IFormFile file)
+ {
+ var completeUrl = $@"/home/{networkCredential.UserName}/" + basePath + '/' + id.ToString() + '/' + file.FileName;
+
+ if (!client.Exists($@"/home/{networkCredential.UserName}/" + basePath + '/' + id.ToString()))
+ client.CreateDirectory($@"/home/{networkCredential.UserName}/" + basePath + '/' + id.ToString());
+
+ if (client.Exists(completeUrl))
+ client.DeleteFile(completeUrl);
+
+ client.Create(completeUrl);
+ client.UploadFile(file.OpenReadStream(), completeUrl, true);
+
+ return Task.FromResult(true);
+ }
+ }
+}
diff --git a/Library.Encyclopedia.DataAccess/FileAccess/WindowsFileSaveAdapter.cs b/Library.Encyclopedia.DataAccess/FileAccess/WindowsFileSaveAdapter.cs
new file mode 100644
index 0000000..2782462
--- /dev/null
+++ b/Library.Encyclopedia.DataAccess/FileAccess/WindowsFileSaveAdapter.cs
@@ -0,0 +1,83 @@
+using Library.Encyclopedia.Entity.Interfaces;
+using Library.Encyclopedia.Entity.Models;
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Library.Encyclopedia.DataAccess.FileAccess
+{
+ public class WindowsFileSaveAdapter : IFilesAdapter
+ {
+ private readonly string networkPath;
+ private readonly string tempAssetFileLocation;
+
+ public WindowsFileSaveAdapter(string networkPath, string tempAssetFileLocation)
+ {
+ this.networkPath = networkPath;
+ this.tempAssetFileLocation = tempAssetFileLocation;
+ }
+
+ public void CreateViewableLink(string id, string name)
+ {
+ if (!Directory.Exists(Path.Combine(tempAssetFileLocation, id)))
+ Directory.CreateDirectory(Path.Combine(tempAssetFileLocation, id));
+
+ File.Copy(Path.Combine(networkPath, id, name), Path.Combine(tempAssetFileLocation, id, name), true);
+ }
+
+ public void DeleteFile(string id, string name)
+ {
+ File.Delete(Path.Combine(networkPath, id, name));
+ }
+
+ public void DeleteFiles(string id)
+ {
+ foreach (var file in Directory.GetFiles(Path.Combine(networkPath, id)))
+ {
+ File.Delete(file);
+ }
+ Directory.Delete(Path.Combine(networkPath, id));
+ }
+
+ public void DestroyViewableLink(string id, string name)
+ {
+ File.Delete(Path.Combine(tempAssetFileLocation, id, name));
+ }
+
+ public Stream DownloadFile(string id, string name)
+ {
+ return File.OpenRead(Path.Combine(networkPath, id, name));
+ }
+
+ public async Task UploadFile(Guid id, IFormFile file)
+ {
+ try
+ {
+ var path = Path.Combine(networkPath, id.ToString(), file.FileName);
+ if (File.Exists(path))
+ using (var stream = File.OpenWrite(path))
+ {
+ await file.CopyToAsync(stream);
+ }
+ else
+ {
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
+ using (var stream = File.Create(path))
+ {
+ await file.CopyToAsync(stream);
+ }
+ }
+
+ return true;
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+ }
+ }
+}
diff --git a/Library.Encyclopedia.DataAccess/IApplicationDbContext.cs b/Library.Encyclopedia.DataAccess/IApplicationDbContext.cs
index 4c1fcf0..562475d 100644
--- a/Library.Encyclopedia.DataAccess/IApplicationDbContext.cs
+++ b/Library.Encyclopedia.DataAccess/IApplicationDbContext.cs
@@ -1,5 +1,6 @@
using Library.Encyclopedia.Entity.Models;
using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Storage;
using System.Threading.Tasks;
namespace Library.Encyclopedia.DataAccess
@@ -9,6 +10,10 @@ public interface IApplicationDbContext
DbSet Main { get; set; }
DbSet Files { get; set; }
DbSet Links { get; set; }
+ DbSet QueryStats { get; set; }
+ DbSet Comments { get; set; }
+ DbSet Likes { get; set; }
+
Task SaveChanges();
}
}
\ No newline at end of file
diff --git a/Library.Encyclopedia.DataAccess/Library.Encyclopedia.DataAccess.csproj b/Library.Encyclopedia.DataAccess/Library.Encyclopedia.DataAccess.csproj
index e53781f..1b6b377 100644
--- a/Library.Encyclopedia.DataAccess/Library.Encyclopedia.DataAccess.csproj
+++ b/Library.Encyclopedia.DataAccess/Library.Encyclopedia.DataAccess.csproj
@@ -5,6 +5,8 @@
+
+
@@ -17,7 +19,10 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
diff --git a/Library.Encyclopedia.DataAccess/QueryStatsAccess/CommonlyOccuringWordsAdapter.cs b/Library.Encyclopedia.DataAccess/QueryStatsAccess/CommonlyOccuringWordsAdapter.cs
new file mode 100644
index 0000000..681bd64
--- /dev/null
+++ b/Library.Encyclopedia.DataAccess/QueryStatsAccess/CommonlyOccuringWordsAdapter.cs
@@ -0,0 +1,175 @@
+using Catalyst;
+using Catalyst.Models;
+using Library.Encyclopedia.Entity.Models;
+using Microsoft.Extensions.Caching.Memory;
+using Mosaik.Core;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+
+namespace Library.Encyclopedia.DataAccess.QueryStatsAccess
+{
+ public class CommonlyOccuringWordsAdapter
+ {
+ private readonly IApplicationDbContext applicationDbContext;
+ private Dictionary commonlyOccuringWords;
+ private Dictionary> forReference;
+ private IMemoryCache _cache;
+
+ public CommonlyOccuringWordsAdapter(IApplicationDbContext applicationDbContext, IMemoryCache cache)
+ {
+ commonlyOccuringWords = new Dictionary();
+ forReference = new Dictionary>();
+ this.applicationDbContext = applicationDbContext;
+ this._cache = cache;
+ }
+
+ private void PopulateRecommendedWords()
+ {
+ commonlyOccuringWords = new Dictionary();
+ forReference = new Dictionary>();
+
+ var allData = applicationDbContext.Main.ToList();
+
+ //BasicParser(allData);
+ AdvancedParser(allData);
+
+ var cacheEntryOptions = new MemoryCacheEntryOptions()
+ .SetSlidingExpiration(TimeSpan.FromHours(1));
+
+ if (commonlyOccuringWords != null)
+ {
+ _cache.Set("commonlyOccuringWords", commonlyOccuringWords, cacheEntryOptions);
+ }
+ }
+
+ private void AdvancedParser(List allData)
+ {
+ English.Register();
+ Storage.Current = new DiskStorage("catalyst-models");
+ var nlp = Pipeline.For(Language.English);
+
+ foreach (var item in allData)
+ {
+ ProcessText(nlp, item.Title, item.Id);
+ ProcessText(nlp, item.RawDescription, item.Id);
+ }
+ }
+
+ private void ProcessText(Pipeline nlp, string text, Guid id)
+ {
+ var doc = new Document(text, Language.English);
+ nlp.ProcessSingle(doc);
+
+ foreach (var sentence in doc)
+ {
+ foreach (var token in sentence)
+ {
+ switch (token.POS)
+ {
+ case PartOfSpeech.PROPN:
+ case PartOfSpeech.NOUN:
+ case PartOfSpeech.ADJ:
+ case PartOfSpeech.ADV:
+ case PartOfSpeech.NUM:
+ if (token.Value.Length >= 3)
+ {
+ if (commonlyOccuringWords.ContainsKey(token.Value))
+ commonlyOccuringWords[token.Value]++;
+ else
+ commonlyOccuringWords.Add(token.Value, 1);
+ }
+ break;
+ case PartOfSpeech.NONE:
+ case PartOfSpeech.ADP:
+ case PartOfSpeech.AUX:
+ case PartOfSpeech.CCONJ:
+ case PartOfSpeech.DET:
+ case PartOfSpeech.INTJ:
+ case PartOfSpeech.PART:
+ case PartOfSpeech.PRON:
+ case PartOfSpeech.PUNCT:
+ case PartOfSpeech.SCONJ:
+ case PartOfSpeech.SYM:
+ case PartOfSpeech.VERB:
+ case PartOfSpeech.X:
+ default:
+ break;
+ }
+
+ if (!forReference.ContainsKey(token.POS))
+ forReference.Add(token.POS, new List() { token.Value.ToLower() });
+ else
+ {
+ if (!forReference[token.POS].Contains(token.Value.ToLower()))
+ forReference[token.POS].Add(token.Value.ToLower());
+ }
+ }
+ }
+ }
+
+ private void BasicParser(List allData)
+ {
+ foreach (var item in allData)
+ {
+ string[] seperators = { ", ", ". ", "! ", "? ", ": ", "; ", " " };
+
+ string v1 = item.Title.Replace('(', ' ')
+ .Replace(')', ' ')
+ .Replace('{', ' ')
+ .Replace('}', ' ')
+ .Replace('[', ' ')
+ .Replace(']', ' ');
+ foreach (var word in v1.Split(seperators, StringSplitOptions.RemoveEmptyEntries))
+ {
+ if (!string.IsNullOrEmpty(word) && !string.IsNullOrWhiteSpace(word) && !word.ToCharArray().All(s => !char.IsLetterOrDigit(s)))
+ {
+ if (commonlyOccuringWords.ContainsKey(word))
+ commonlyOccuringWords[word]++;
+ else
+ commonlyOccuringWords.Add(word, 1);
+ }
+ }
+
+ string v2 = item.RawDescription.Replace('(', ' ')
+ .Replace(')', ' ')
+ .Replace('{', ' ')
+ .Replace('}', ' ')
+ .Replace('[', ' ')
+ .Replace(']', ' ');
+
+ foreach (var word in v2.Split(seperators, StringSplitOptions.RemoveEmptyEntries))
+ {
+ if (!string.IsNullOrEmpty(word) && !string.IsNullOrWhiteSpace(word) && !word.ToCharArray().All(s => !char.IsLetterOrDigit(s)))
+ {
+ if (commonlyOccuringWords.ContainsKey(word))
+ commonlyOccuringWords[word]++;
+ else
+ commonlyOccuringWords.Add(word, 1);
+ }
+ }
+ }
+ }
+
+ public Dictionary GetCommonlyUsedWords(int count = 0)
+ {
+ bool resultCacheValueFlag = _cache.TryGetValue("commonlyOccuringWords", out object value);
+ if (!resultCacheValueFlag || value == null)
+ PopulateRecommendedWords();
+
+ return _cache.Get>("commonlyOccuringWords").OrderByDescending(s => s.Value).Take(count).ToDictionary(x => x.Key, x => x.Value);
+ }
+
+ public Dictionary GetCommonlySearchedWords(int count = 0)
+ {
+ IQueryable queryable = applicationDbContext.QueryStats.OrderByDescending(s => s.Count).Take(count);
+ return queryable.ToDictionary(s => s.Query, s => s.Count);
+ }
+
+ public Dictionary> GetNLPResult()
+ {
+ return forReference.ToDictionary(s => s.Key.ToString(), s => s.Value);
+ }
+ }
+}
diff --git a/Library.Encyclopedia.DataAccess/QueryStatsAccess/QueryStatsAdapter.cs b/Library.Encyclopedia.DataAccess/QueryStatsAccess/QueryStatsAdapter.cs
new file mode 100644
index 0000000..a659441
--- /dev/null
+++ b/Library.Encyclopedia.DataAccess/QueryStatsAccess/QueryStatsAdapter.cs
@@ -0,0 +1,31 @@
+using Library.Encyclopedia.Entity.Models;
+using Microsoft.EntityFrameworkCore;
+using System.Collections.Concurrent;
+using System.Threading.Tasks;
+
+namespace Library.Encyclopedia.DataAccess.QueryStatsAccess
+{
+ public class QueryStatsAdapter
+ {
+ private readonly IApplicationDbContext _dbcontext;
+
+ public QueryStatsAdapter(IApplicationDbContext applicationDbContext)
+ {
+ this._dbcontext = applicationDbContext;
+ }
+
+ public async Task AddQuery(string query)
+ {
+ QueryStats queryStats = await _dbcontext.QueryStats.FirstOrDefaultAsync(s => s.Query == query);
+ if (queryStats == null)
+ await _dbcontext.QueryStats.AddAsync(new QueryStats { Query = query, Count = 1 });
+ else
+ {
+ queryStats.Count++;
+ _dbcontext.QueryStats.Update(queryStats);
+ }
+
+ await _dbcontext.SaveChanges();
+ }
+ }
+}
diff --git a/Library.Encyclopedia.Entity/Exceptions/CreateFailedException.cs b/Library.Encyclopedia.Entity/Exceptions/CreateFailedException.cs
new file mode 100644
index 0000000..1fd9049
--- /dev/null
+++ b/Library.Encyclopedia.Entity/Exceptions/CreateFailedException.cs
@@ -0,0 +1,19 @@
+using EnumsNET;
+using System;
+using System.ComponentModel;
+
+namespace Library.Encyclopedia.Entity.Exceptions
+{
+ public class CreateFailedException : Exception
+ {
+ public CreateFailedException(CreateFailErrorCode code) : base(((CreateFailErrorCode)code).AsString(EnumFormat.Description))
+ {
+ }
+ }
+
+ public enum CreateFailErrorCode
+ {
+ [Description("$$$ is not an accepted input")]
+ INVALID_INPUT_SEQUENCE
+ }
+}
\ No newline at end of file
diff --git a/Library.Encyclopedia.Entity/Exceptions/GetFailedException.cs b/Library.Encyclopedia.Entity/Exceptions/GetFailedException.cs
new file mode 100644
index 0000000..8fdf675
--- /dev/null
+++ b/Library.Encyclopedia.Entity/Exceptions/GetFailedException.cs
@@ -0,0 +1,18 @@
+using EnumsNET;
+using System;
+using System.ComponentModel;
+
+namespace Library.Encyclopedia.Entity.Exceptions
+{
+ public class GetFailedException : Exception
+ {
+ public GetFailedException(GetFailErrorCode code) : base(((GetFailErrorCode)code).AsString(EnumFormat.Description))
+ {
+ }
+ }
+
+ public enum GetFailErrorCode
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/Library.Encyclopedia.Entity/Exceptions/UpdateFailedException.cs b/Library.Encyclopedia.Entity/Exceptions/UpdateFailedException.cs
index 7bd1aa6..eb04a1e 100644
--- a/Library.Encyclopedia.Entity/Exceptions/UpdateFailedException.cs
+++ b/Library.Encyclopedia.Entity/Exceptions/UpdateFailedException.cs
@@ -14,6 +14,8 @@ public UpdateFailedException(UpdateFailErrorCode code) : base(((UpdateFailErrorC
public enum UpdateFailErrorCode
{
[Description("Entry not found!")]
- EntryNotFound
+ EntryNotFound,
+ [Description("$$$ is not an accepted input")]
+ INVALID_INPUT_SEQUENCE
}
}
diff --git a/Library.Encyclopedia.Entity/Interfaces/ICommentsDataAccess.cs b/Library.Encyclopedia.Entity/Interfaces/ICommentsDataAccess.cs
new file mode 100644
index 0000000..6275b6f
--- /dev/null
+++ b/Library.Encyclopedia.Entity/Interfaces/ICommentsDataAccess.cs
@@ -0,0 +1,19 @@
+using Library.Encyclopedia.Entity.Models;
+using Library.Encyclopedia.Entity.Models.External;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Library.Encyclopedia.Entity.Interfaces
+{
+ public interface ICommentsDataAccess
+ {
+ Task Get(int offset = 0, int limit = 10, bool asc = false);
+ Task> Get(Guid mainId);
+ Task CreateComment(Comments comments);
+ Task UpdateComment(Guid id, string comment, string userSid);
+ Task DeleteComment(Guid id, string userSid, bool isAdmin = false);
+ Task Resolve(Guid id, bool flag = true);
+ }
+}
diff --git a/Library.Encyclopedia.Entity/Interfaces/IFilesAdapter.cs b/Library.Encyclopedia.Entity/Interfaces/IFilesAdapter.cs
index 95bfb79..afbc621 100644
--- a/Library.Encyclopedia.Entity/Interfaces/IFilesAdapter.cs
+++ b/Library.Encyclopedia.Entity/Interfaces/IFilesAdapter.cs
@@ -2,12 +2,19 @@
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
namespace Library.Encyclopedia.Entity.Interfaces
{
public interface IFilesAdapter
{
- IEnumerable UploadFiles(Guid id, List files);
- IEnumerable DownloadFiles(IEnumerable files, string directory);
+ public Task UploadFile(Guid id, IFormFile file);
+ Stream DownloadFile(string id, string name);
+ public void DeleteFiles(string id);
+ public void DeleteFile(string id, string name);
+
+ public void CreateViewableLink(string id, string name);
+ public void DestroyViewableLink(string id, string name);
}
}
\ No newline at end of file
diff --git a/Library.Encyclopedia.Entity/Interfaces/ILikesDataAccess.cs b/Library.Encyclopedia.Entity/Interfaces/ILikesDataAccess.cs
new file mode 100644
index 0000000..ffe27c9
--- /dev/null
+++ b/Library.Encyclopedia.Entity/Interfaces/ILikesDataAccess.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Library.Encyclopedia.Entity.Interfaces
+{
+ public interface ILikesDataAccess
+ {
+ Task Like(Guid commentId, string userSid, bool flag = true);
+ Task> GetLikes(List commentIds);
+ Task DeleteLikes(List commentIds);
+ }
+}
diff --git a/Library.Encyclopedia.Entity/Interfaces/IMainDataAccess.cs b/Library.Encyclopedia.Entity/Interfaces/IMainDataAccess.cs
index cc8c6eb..2ba0aa5 100644
--- a/Library.Encyclopedia.Entity/Interfaces/IMainDataAccess.cs
+++ b/Library.Encyclopedia.Entity/Interfaces/IMainDataAccess.cs
@@ -9,15 +9,15 @@ namespace Library.Encyclopedia.Entity.Interfaces
public interface IMainDataAccess
{
#region GET
- public Task GetAsync(string query, int offset, int pagesize, 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(string query, int offset, int pagesize, int previewSize, bool ascending);
+ public Task GetByCategoryAsync(string category, int offset, int pagesize, int previewSize, bool ascending);
+ public Task GetByAlphabetAsync(char startingAlphabet, int offset, int pagesize, int previewSize, bool ascending);
public Task GetAsync(Guid id);
#endregion
public Task CreateAsync(Main main);
- public Task UpdateAsync(Guid id, MainUpdateModel model);
+ public Task UpdateAsync(Guid id, MainUpdateModel model);
public Task DeleteAsync(Guid id);
public Task> GetAllCategoriesAsync();
diff --git a/Library.Encyclopedia.Entity/Library.Encyclopedia.Entity.csproj b/Library.Encyclopedia.Entity/Library.Encyclopedia.Entity.csproj
index f6f8e6a..66d87ed 100644
--- a/Library.Encyclopedia.Entity/Library.Encyclopedia.Entity.csproj
+++ b/Library.Encyclopedia.Entity/Library.Encyclopedia.Entity.csproj
@@ -7,6 +7,7 @@
+
diff --git a/Library.Encyclopedia.Entity/Models/Comments.cs b/Library.Encyclopedia.Entity/Models/Comments.cs
new file mode 100644
index 0000000..a1f17c1
--- /dev/null
+++ b/Library.Encyclopedia.Entity/Models/Comments.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Text;
+
+namespace Library.Encyclopedia.Entity.Models
+{
+ public class Comments
+ {
+ public Guid Id { get; set; }
+ public Guid MainId { get; set; }
+ public string Comment { get; set; }
+ public DateTime PostedTime { get; set; }
+ public string UserName { get; set; }
+ public string UserSid { get; set; }
+ public long Likes { get; set; }
+ public bool IsResolved { get; set; }
+ }
+}
diff --git a/Library.Encyclopedia.Entity/Models/EmailPropertiesV1.cs b/Library.Encyclopedia.Entity/Models/EmailPropertiesV1.cs
new file mode 100644
index 0000000..c50a039
--- /dev/null
+++ b/Library.Encyclopedia.Entity/Models/EmailPropertiesV1.cs
@@ -0,0 +1,17 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Library.Encyclopedia.Entity.Models
+{
+ public class EmailPropertiesV1
+ {
+ [JsonProperty("content")]
+ public string Content { get; set; }
+ [JsonProperty("name")]
+ public string Name { get; set; }
+ [JsonProperty("email")]
+ public string Email { get; set; }
+ }
+}
diff --git a/Library.Encyclopedia.Entity/Models/External/CommentsExternalCollection.cs b/Library.Encyclopedia.Entity/Models/External/CommentsExternalCollection.cs
new file mode 100644
index 0000000..3d2dbec
--- /dev/null
+++ b/Library.Encyclopedia.Entity/Models/External/CommentsExternalCollection.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Library.Encyclopedia.Entity.Models.External
+{
+
+ public class CommentsExternalCollection : QueryExternalModel
+ {
+ public CommentsExternalCollection()
+ {
+ this.Count = 0;
+ this.Result = new List();
+ this.Total = 0;
+ }
+ public CommentsExternalCollection(List collection, int total)
+ {
+ this.Result = collection;
+ this.Count = collection.Count();
+ this.Total = total;
+ }
+ }
+}
diff --git a/Library.Encyclopedia.Entity/Models/External/MainMinimizedExternal.cs b/Library.Encyclopedia.Entity/Models/External/MainMinimizedExternal.cs
index 7aca354..3e36cbf 100644
--- a/Library.Encyclopedia.Entity/Models/External/MainMinimizedExternal.cs
+++ b/Library.Encyclopedia.Entity/Models/External/MainMinimizedExternal.cs
@@ -8,11 +8,16 @@ 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
{
+ public MainMinimizedExternalCollection()
+ {
+ this.Count = 0;
+ this.Result = new List();
+ this.Total = 0;
+ }
public MainMinimizedExternalCollection(IEnumerable collection, int total)
{
this.Result = collection;
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/Files.cs b/Library.Encyclopedia.Entity/Models/Files.cs
index 3c981cf..f862f9d 100644
--- a/Library.Encyclopedia.Entity/Models/Files.cs
+++ b/Library.Encyclopedia.Entity/Models/Files.cs
@@ -13,6 +13,8 @@ public class Files
public string FileName { get; set; }
[Required]
public string FileType { get; set; }
+ [Required]
+ public long FileSize { get; set; }
public string FileDescription { get; set; }
[Required]
public string FilePath { get; set; }
diff --git a/Library.Encyclopedia.Entity/Models/Likes.cs b/Library.Encyclopedia.Entity/Models/Likes.cs
new file mode 100644
index 0000000..eab4562
--- /dev/null
+++ b/Library.Encyclopedia.Entity/Models/Likes.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Library.Encyclopedia.Entity.Models
+{
+ public class Likes
+ {
+ public long Id { get; set; }
+ public Guid CommentId { get; set; }
+ public string UserSid { get; set; }
+ }
+}
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..9e81b7f 100644
--- a/Library.Encyclopedia.Entity/Models/Main.cs
+++ b/Library.Encyclopedia.Entity/Models/Main.cs
@@ -12,9 +12,12 @@ 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; }
+ public string Author { get; set; }
public ICollection Files { get; set; }
public ICollection Links { get; set; }
@@ -22,20 +25,82 @@ public class Main
public static class MainExtensions
{
- public static MainMinimizedExternal Minimize(this Main main)
+ public static MainMinimizedExternal MinimizeWithQuery(this Main main, string query, int previewText_maxlength)
{
- return new MainMinimizedExternal {
- Id = main.Id,
- Category = main.Category,
- Description = main.Description,
- Title = main.Title
- };
+ if (!string.IsNullOrEmpty(main.RawDescription))
+ {
+ 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
+ };
+ }
+ }
+ else
+ return new MainMinimizedExternal {
+ Id = main.Id,
+ Preview = string.Empty,
+ Title = main.Title
+ };
+ }
+ public static MainMinimizedExternal Minimize(this Main main, int previewText_maxlength)
+ {
+ return main.MinimizeWithQuery(null, previewText_maxlength);
+ }
+ 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)
+ public static IEnumerable Minimize(this IEnumerable collection, int previewText_maxlength)
{
foreach (var item in collection)
{
- yield return Minimize(item);
+ yield return Minimize(item, previewText_maxlength);
}
}
}
diff --git a/Library.Encyclopedia.Entity/Models/QueryStats.cs b/Library.Encyclopedia.Entity/Models/QueryStats.cs
new file mode 100644
index 0000000..52d304f
--- /dev/null
+++ b/Library.Encyclopedia.Entity/Models/QueryStats.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Library.Encyclopedia.Entity.Models
+{
+ public class QueryStats
+ {
+ public long Id { get; set; }
+ public string Query { get; set; }
+ public long Count { get; set; }
+ }
+}