/src/Web/PressCenters.Web/ViewModels/News/NewsViewModel.cs

https://github.com/NikolayIT/PressCenters.com · C# · 136 lines · 100 code · 31 blank · 5 comment · 9 complexity · 03f4b99d10c5212444d9a62c99f989f1 MD5 · raw file

  1. namespace PressCenters.Web.ViewModels.News
  2. {
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Globalization;
  6. using System.Linq;
  7. using System.Net;
  8. using System.Text.RegularExpressions;
  9. using AngleSharp;
  10. using AngleSharp.Html.Parser;
  11. using AutoMapper;
  12. using Ganss.XSS;
  13. using PressCenters.Common;
  14. using PressCenters.Data.Models;
  15. using PressCenters.Services;
  16. using PressCenters.Services.Mapping;
  17. public class NewsViewModel : IMapFrom<News>, IHaveCustomMappings
  18. {
  19. public int Id { get; set; }
  20. public string Title { get; set; }
  21. public string Content { get; set; }
  22. public string SanitizedContent
  23. {
  24. get
  25. {
  26. // Sanitize
  27. var htmlSanitizer = new HtmlSanitizer();
  28. htmlSanitizer.AllowedCssProperties.Remove("font-size");
  29. htmlSanitizer.AllowedSchemes.Add("mailto");
  30. htmlSanitizer.AllowDataAttributes = false;
  31. var html = htmlSanitizer.Sanitize(this.Content);
  32. // Parse document
  33. var parser = new HtmlParser();
  34. var document = parser.ParseDocument(html);
  35. // Add .table class for tables
  36. var tables = document.QuerySelectorAll("table");
  37. foreach (var table in tables)
  38. {
  39. table.ClassName += " table table-striped table-bordered table-hover table-sm";
  40. }
  41. // Clear font size
  42. var fontElements = document.QuerySelectorAll("font");
  43. foreach (var fontElement in fontElements)
  44. {
  45. if (fontElement.HasAttribute("size"))
  46. {
  47. fontElement.RemoveAttribute("size");
  48. }
  49. }
  50. return document.ToHtml();
  51. }
  52. }
  53. public string ShortContent => this.GetShortContent(235);
  54. public string ImageUrl { get; set; }
  55. public string SmallImageUrl =>
  56. this.ImageUrl == null ? this.SourceDefaultImageUrl : $"/images/news/{this.Id % 1000}/small_{this.Id}.png";
  57. public string BigImageUrl =>
  58. this.ImageUrl == null ? this.SourceDefaultImageUrl : $"/images/news/{this.Id % 1000}/big_{this.Id}.png";
  59. public string OriginalUrl { get; set; }
  60. public string RemoteId { get; set; }
  61. public string SourceName { get; set; }
  62. public string SourceShortName { get; set; }
  63. public string SourceDefaultImageUrl { get; set; }
  64. public string SourceUrl { get; set; }
  65. public IEnumerable<string> Tags { get; set; }
  66. public string ShorterOriginalUrl
  67. {
  68. get
  69. {
  70. if (this.OriginalUrl == null)
  71. {
  72. return string.Empty;
  73. }
  74. if (this.OriginalUrl.Length <= 65)
  75. {
  76. return this.OriginalUrl;
  77. }
  78. return $"{this.OriginalUrl.Substring(0, 30)}..{this.OriginalUrl.Substring(this.OriginalUrl.Length - 30, 30)}";
  79. }
  80. }
  81. public DateTime CreatedOn { get; set; }
  82. public string CreatedOnAsString =>
  83. this.CreatedOn.Hour == 0 && this.CreatedOn.Minute == 0
  84. ? this.CreatedOn.ToString("ddd, dd MMM yyyy", new CultureInfo("bg-BG"))
  85. : this.CreatedOn.ToString("ddd, dd MMM yyyy HH:mm", new CultureInfo("bg-BG"));
  86. public string Url => $"/News/{this.Id}/{new SlugGenerator().GenerateSlug(this.Title)}";
  87. public void CreateMappings(IProfileExpression configuration)
  88. {
  89. configuration.CreateMap<News, NewsViewModel>().ForMember(
  90. m => m.Tags,
  91. opt => opt.MapFrom(x => x.Tags.Select(t => t.Tag.Name)));
  92. }
  93. public string GetShortContent(int maxLength)
  94. {
  95. // TODO: Extract as a service
  96. var htmlSanitizer = new HtmlSanitizer();
  97. var html = htmlSanitizer.Sanitize(this.Content);
  98. var strippedContent = WebUtility.HtmlDecode(html?.StripHtml() ?? string.Empty);
  99. strippedContent = strippedContent.Replace("\n", " ");
  100. strippedContent = strippedContent.Replace("\t", " ");
  101. strippedContent = Regex.Replace(strippedContent, @"\s+", " ").Trim();
  102. return strippedContent.Length <= maxLength ? strippedContent : strippedContent.Substring(0, maxLength) + "...";
  103. }
  104. }
  105. }