public DisplayPackageViewModel Setup( DisplayPackageViewModel viewModel, Package package, User currentUser, PackageDeprecation deprecation, RenderedReadMeResult readmeResult) { _listPackageItemViewModelFactory.Setup(viewModel, package, currentUser); SetupCommon(viewModel, package, pushedBy: null); return(SetupInternal(viewModel, package, currentUser, deprecation, readmeResult)); }
public DisplayPackageViewModel Setup( DisplayPackageViewModel viewModel, Package package, IReadOnlyCollection <Package> allVersions, User currentUser, IReadOnlyDictionary <int, PackageDeprecation> packageKeyToDeprecation, RenderedReadMeResult readmeResult) { _listPackageItemViewModelFactory.Setup(viewModel, package, currentUser); SetupCommon(viewModel, package, pushedBy: null, packageKeyToDeprecation: packageKeyToDeprecation); return(SetupInternal(viewModel, package, allVersions, currentUser, packageKeyToDeprecation, readmeResult)); }
/// <summary> /// Get the converted HTML from the stored ReadMe markdown. /// </summary> /// <param name="package">Package entity associated with the ReadMe.</param> /// <returns>ReadMe converted to HTML.</returns> public async Task <RenderedReadMeResult> GetReadMeHtmlAsync(Package package) { var readMeMd = await GetReadMeMdAsync(package); var result = new RenderedReadMeResult { Content = readMeMd, ImagesRewritten = false }; return(string.IsNullOrEmpty(readMeMd) ? result : GetReadMeHtml(readMeMd)); }
/// <summary> /// Get the converted HTML from the package with Readme markdown. /// </summary> /// <param name="readmeFileName">The path of Readme markdown.</param> /// <param name="packageArchiveReader"> /// The <see cref="PackageArchiveReader"/> instance providing the package metadata. /// </param> /// <returns>ReadMe converted to HTML.</returns> public async Task <RenderedReadMeResult> GetReadMeHtmlAsync(string readmeFileName, PackageArchiveReader packageArchiveReader, Encoding encoding) { var readmeMd = await GetReadMeMdAsync(readmeFileName, packageArchiveReader, encoding); var result = new RenderedReadMeResult { Content = readmeMd, ImagesRewritten = false }; return(string.IsNullOrEmpty(readmeMd) ? result : GetReadMeHtml(readmeMd)); }
public DisplayPackageViewModel Create( Package package, User currentUser, PackageDeprecation deprecation, RenderedReadMeResult readmeResult) { var viewModel = new DisplayPackageViewModel(); return(Setup( viewModel, package, currentUser, deprecation, readmeResult)); }
public DisplayPackageViewModel Create( Package package, IReadOnlyCollection <Package> allVersions, User currentUser, IReadOnlyDictionary <int, PackageDeprecation> packageKeyToDeprecation, RenderedReadMeResult readmeResult) { var viewModel = new DisplayPackageViewModel(); return(Setup( viewModel, package, allVersions, currentUser, packageKeyToDeprecation, readmeResult)); }
private DisplayPackageViewModel SetupInternal( DisplayPackageViewModel viewModel, Package package, IReadOnlyCollection <Package> allVersions, User currentUser, IReadOnlyDictionary <int, PackageDeprecation> packageKeyToDeprecation, RenderedReadMeResult readmeResult) { var dependencies = package.Dependencies.ToList(); viewModel.Dependencies = new DependencySetsViewModel(dependencies); viewModel.HasSemVer2Version = viewModel.NuGetVersion.IsSemVer2; viewModel.HasSemVer2Dependency = dependencies .Where(pd => !string.IsNullOrEmpty(pd.VersionSpec)) .Select(pd => VersionRange.Parse(pd.VersionSpec)) .Any(p => (p.HasUpperBound && p.MaxVersion.IsSemVer2) || (p.HasLowerBound && p.MinVersion.IsSemVer2)); var packageHistory = allVersions .OrderByDescending(p => new NuGetVersion(p.Version)) .ToList(); var pushedByCache = new Dictionary <User, string>(); viewModel.PackageVersions = packageHistory .Select( p => { var vm = new DisplayPackageViewModel(); _listPackageItemViewModelFactory.Setup(vm, p, currentUser); return(SetupCommon(vm, p, GetPushedBy(p, currentUser, pushedByCache), packageKeyToDeprecation)); }) .ToList(); viewModel.PushedBy = GetPushedBy(package, currentUser, pushedByCache); viewModel.PackageFileSize = package.PackageFileSize; viewModel.LatestSymbolsPackage = package.LatestSymbolPackage(); viewModel.LatestAvailableSymbolsPackage = viewModel.LatestSymbolsPackage != null && viewModel.LatestSymbolsPackage.StatusKey == PackageStatus.Available ? viewModel.LatestSymbolsPackage : package.LatestAvailableSymbolPackage(); if (packageHistory.Any()) { // calculate the number of days since the package registration was created // round to the nearest integer, with a min value of 1 // divide the total download count by this number viewModel.TotalDaysSinceCreated = Convert.ToInt32(Math.Max(1, Math.Round((DateTime.UtcNow - packageHistory.Min(p => p.Created)).TotalDays))); viewModel.DownloadsPerDay = viewModel.TotalDownloadCount / viewModel.TotalDaysSinceCreated; // for the package viewModel.DownloadsPerDayLabel = viewModel.DownloadsPerDay < 1 ? "<1" : viewModel.DownloadsPerDay.ToNuGetNumberString(); // Lazily load the package types from the database. viewModel.IsDotnetToolPackageType = package.PackageTypes.Any(e => e.Name.Equals("DotnetTool", StringComparison.OrdinalIgnoreCase)); viewModel.IsDotnetNewTemplatePackageType = package.PackageTypes.Any(e => e.Name.Equals("Template", StringComparison.OrdinalIgnoreCase)); } if (packageKeyToDeprecation != null && packageKeyToDeprecation.TryGetValue(package.Key, out var deprecation)) { viewModel.AlternatePackageId = deprecation.AlternatePackageRegistration?.Id; var alternatePackage = deprecation.AlternatePackage; if (alternatePackage != null) { // A deprecation should not have both an alternate package registration and an alternate package. // In case a deprecation does have both, we will hide the alternate package registration's ID in this model. viewModel.AlternatePackageId = alternatePackage?.Id; viewModel.AlternatePackageVersion = alternatePackage?.Version; } viewModel.CustomMessage = deprecation.CustomMessage; } viewModel.ReadMeHtml = readmeResult?.Content; viewModel.ReadMeImagesRewritten = readmeResult != null ? readmeResult.ImagesRewritten : false; viewModel.HasEmbeddedIcon = package.HasEmbeddedIcon; return(viewModel); }
/// <summary> /// Get converted HTML for readme.md string content. /// </summary> /// <param name="readMeMd">ReadMe.md content.</param> /// <returns>HTML content.</returns> internal static RenderedReadMeResult GetReadMeHtml(string readMeMd) { var output = new RenderedReadMeResult() { ImagesRewritten = false, Content = "" }; // HTML encode markdown, except for block quotes, to block inline html. var encodedMarkdown = EncodedBlockQuotePattern.Replace(HttpUtility.HtmlEncode(readMeMd), "> "); var settings = CommonMarkSettings.Default.Clone(); settings.RenderSoftLineBreaksAsLineBreaks = true; // Parse executes CommonMarkConverter's ProcessStage1 and ProcessStage2. var document = CommonMarkConverter.Parse(encodedMarkdown, settings); foreach (var node in document.AsEnumerable()) { if (node.IsOpening) { var block = node.Block; if (block != null) { switch (block.Tag) { // Demote heading tags so they don't overpower expander headings. case BlockTag.AtxHeading: case BlockTag.SetextHeading: var level = (byte)Math.Min(block.Heading.Level + 1, 6); block.Heading = new HeadingData(level); break; // Decode preformatted blocks to prevent double encoding. // Skip BlockTag.BlockQuote, which are partially decoded upfront. case BlockTag.FencedCode: case BlockTag.IndentedCode: if (block.StringContent != null) { var content = block.StringContent.TakeFromStart(block.StringContent.Length); var unencodedContent = HttpUtility.HtmlDecode(content); block.StringContent.Replace(unencodedContent, 0, unencodedContent.Length); } break; } } var inline = node.Inline; if (inline != null) { if (inline.Tag == InlineTag.Link) { // Allow only http or https links in markdown. Transform link to https for known domains. if (!PackageHelper.TryPrepareUrlForRendering(inline.TargetUrl, out string readyUriString)) { inline.TargetUrl = string.Empty; } else { inline.TargetUrl = readyUriString; } } else if (inline.Tag == InlineTag.Image) { if (!PackageHelper.TryPrepareUrlForRendering(inline.TargetUrl, out string readyUriString, rewriteAllHttp: true)) { inline.TargetUrl = string.Empty; } else { output.ImagesRewritten = output.ImagesRewritten || (inline.TargetUrl != readyUriString); inline.TargetUrl = readyUriString; } } } } }