diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200218014727_init.Designer.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200312050853_init.Designer.cs similarity index 99% rename from modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200218014727_init.Designer.cs rename to modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200312050853_init.Designer.cs index 522b3e3ba5..0309e4cbc4 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200218014727_init.Designer.cs +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200312050853_init.Designer.cs @@ -10,7 +10,7 @@ using VoloDocs.EntityFrameworkCore; namespace VoloDocs.EntityFrameworkCore.Migrations { [DbContext(typeof(VoloDocsDbContext))] - [Migration("20200218014727_init")] + [Migration("20200312050853_init")] partial class init { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -492,6 +492,9 @@ namespace VoloDocs.EntityFrameworkCore.Migrations b.Property("LastCachedTime") .HasColumnType("datetime2"); + b.Property("LastSignificantUpdateTime") + .HasColumnType("datetime2"); + b.Property("LastUpdatedTime") .HasColumnType("datetime2"); diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200218014727_init.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200312050853_init.cs similarity index 99% rename from modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200218014727_init.cs rename to modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200312050853_init.cs index 7e85e1bbc1..938fbc6a1b 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200218014727_init.cs +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200312050853_init.cs @@ -132,6 +132,7 @@ namespace VoloDocs.EntityFrameworkCore.Migrations LocalDirectory = table.Column(maxLength: 512, nullable: true), CreationTime = table.Column(nullable: false), LastUpdatedTime = table.Column(nullable: false), + LastSignificantUpdateTime = table.Column(nullable: true), LastCachedTime = table.Column(nullable: false) }, constraints: table => diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs index 0780f28624..165f0428cc 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs @@ -490,6 +490,9 @@ namespace VoloDocs.EntityFrameworkCore.Migrations b.Property("LastCachedTime") .HasColumnType("datetime2"); + b.Property("LastSignificantUpdateTime") + .HasColumnType("datetime2"); + b.Property("LastUpdatedTime") .HasColumnType("datetime2"); diff --git a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs index 342130d530..9863995d15 100644 --- a/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs +++ b/modules/docs/src/Volo.Docs.Application/Volo/Docs/Documents/DocumentAppService.cs @@ -96,6 +96,7 @@ namespace Volo.Docs.Documents { leaf.CreationTime = documentUpdateInfo.CreationTime; leaf.LastUpdatedTime = documentUpdateInfo.LastUpdatedTime; + leaf.LastSignificantUpdateTime = documentUpdateInfo.LastSignificantUpdateTime; } } @@ -189,12 +190,12 @@ namespace Volo.Docs.Documents { version = string.IsNullOrWhiteSpace(version) ? project.LatestVersionBranchName : version; - async Task GetDocumentAsync() + async Task GetDocumentAsync(Document oldDocument = null) { Logger.LogInformation($"Not found in the cache. Requesting {documentName} from the source..."); var source = _documentStoreFactory.Create(project.DocumentStoreType); - var sourceDocument = await source.GetDocumentAsync(project, documentName, languageCode, version); + var sourceDocument = await source.GetDocumentAsync(project, documentName, languageCode, version, oldDocument?.LastSignificantUpdateTime); await _documentRepository.DeleteAsync(project.Id, sourceDocument.Name, sourceDocument.LanguageCode, sourceDocument.Version); await _documentRepository.InsertAsync(sourceDocument, true); @@ -206,7 +207,8 @@ namespace Volo.Docs.Documents { Name = sourceDocument.Name, CreationTime = sourceDocument.CreationTime, - LastUpdatedTime = sourceDocument.LastUpdatedTime + LastUpdatedTime = sourceDocument.LastUpdatedTime, + LastSignificantUpdateTime = sourceDocument.LastSignificantUpdateTime }); return CreateDocumentWithDetailsDto(project, sourceDocument); @@ -229,7 +231,7 @@ namespace Volo.Docs.Documents //TODO: Configurable cache time? document.LastCachedTime + TimeSpan.FromHours(2) < DateTime.Now) { - return await GetDocumentAsync(); + return await GetDocumentAsync(document); } var cacheKey = $"DocumentUpdateInfo{document.ProjectId}#{document.Name}#{document.LanguageCode}#{document.Version}"; @@ -238,6 +240,7 @@ namespace Volo.Docs.Documents Name = document.Name, CreationTime = document.CreationTime, LastUpdatedTime = document.LastUpdatedTime, + LastSignificantUpdateTime = document.LastSignificantUpdateTime }); return CreateDocumentWithDetailsDto(project, document); diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/DocumentUpdateInfo.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/DocumentUpdateInfo.cs index fcabe91549..9269c89b07 100644 --- a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/DocumentUpdateInfo.cs +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/DocumentUpdateInfo.cs @@ -10,5 +10,7 @@ namespace Volo.Docs.Documents public virtual DateTime CreationTime { get; set; } public virtual DateTime LastUpdatedTime { get; set; } + + public DateTime? LastSignificantUpdateTime { get; set; } } } \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/NavigationNode.cs b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/NavigationNode.cs index b5c2704eb8..9e54e72be5 100644 --- a/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/NavigationNode.cs +++ b/modules/docs/src/Volo.Docs.Domain.Shared/Volo/Docs/Documents/NavigationNode.cs @@ -26,6 +26,8 @@ namespace Volo.Docs.Documents public virtual DateTime? LastUpdatedTime { get; set; } + public DateTime? LastSignificantUpdateTime { get; set; } + public bool IsSelected(string documentName) { if (documentName == null) diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Document.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Document.cs index ecbc3aa617..ee8710bff3 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Document.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Document.cs @@ -34,6 +34,8 @@ namespace Volo.Docs.Documents public virtual DateTime CreationTime { get; set; } public virtual DateTime LastUpdatedTime { get; set; } + + public virtual DateTime? LastSignificantUpdateTime { get; set; } public virtual DateTime LastCachedTime { get; set; } @@ -60,7 +62,8 @@ namespace Volo.Docs.Documents [NotNull] string localDirectory, DateTime creationTime, DateTime lastUpdatedTime, - DateTime lastCachedTime + DateTime lastCachedTime, + DateTime? lastSignificantUpdateTime = null ) { Id = id; @@ -80,6 +83,7 @@ namespace Volo.Docs.Documents CreationTime = creationTime; LastUpdatedTime = lastUpdatedTime; LastCachedTime = lastCachedTime; + LastSignificantUpdateTime = lastSignificantUpdateTime; Contributors = new List(); ExtraProperties = new Dictionary(); diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/IDocumentSource.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/IDocumentSource.cs index e9d2779bd3..4afe789d37 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/IDocumentSource.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/IDocumentSource.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.Domain.Services; @@ -8,7 +9,7 @@ namespace Volo.Docs.Documents { public interface IDocumentSource : IDomainService { - Task GetDocumentAsync(Project project, string documentName, string languageCode, string version); + Task GetDocumentAsync(Project project, string documentName, string languageCode, string version, DateTime? lastKnownSignificantUpdateTime = null); Task> GetVersionsAsync(Project project); diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/FileSystem/Documents/FileSystemDocumentSource.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/FileSystem/Documents/FileSystemDocumentSource.cs index d93b378dcd..3fa341a848 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/FileSystem/Documents/FileSystemDocumentSource.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/FileSystem/Documents/FileSystemDocumentSource.cs @@ -16,7 +16,7 @@ namespace Volo.Docs.FileSystem.Documents { public const string Type = "FileSystem"; - public async Task GetDocumentAsync(Project project, string documentName, string languageCode, string version) + public async Task GetDocumentAsync(Project project, string documentName, string languageCode, string version, DateTime? lastKnownSignificantUpdateTime = null) { var projectFolder = project.GetFileSystemPath(); var path = Path.Combine(projectFolder, languageCode, documentName); diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubDocumentSource.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubDocumentSource.cs index 0c837991d1..3e287789e9 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubDocumentSource.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubDocumentSource.cs @@ -21,13 +21,15 @@ namespace Volo.Docs.GitHub.Documents public const string Type = "GitHub"; private readonly IGithubRepositoryManager _githubRepositoryManager; + private readonly IGithubPatchAnalyzer _githubPatchAnalyzer; - public GithubDocumentSource(IGithubRepositoryManager githubRepositoryManager) + public GithubDocumentSource(IGithubRepositoryManager githubRepositoryManager, IGithubPatchAnalyzer githubPatchAnalyzer) { _githubRepositoryManager = githubRepositoryManager; + _githubPatchAnalyzer = githubPatchAnalyzer; } - - public virtual async Task GetDocumentAsync(Project project, string documentName, string languageCode, string version) + + public virtual async Task GetDocumentAsync(Project project, string documentName, string languageCode, string version, DateTime? lastKnownSignificantUpdateTime = null) { var token = project.GetGitHubAccessTokenOrNull(); var rootUrl = project.GetGitHubUrl(version); @@ -46,25 +48,38 @@ namespace Volo.Docs.GitHub.Documents fileName = documentName.Substring(documentName.LastIndexOf('/') + 1); } - var fileCommits = await GetFileCommitsAsync(project, version, $"docs/{languageCode}/{documentName}"); + var fileCommits = await GetFileCommitsAsync(project, version, project.GetGitHubInnerUrl(languageCode, documentName)); + + var documentCreationTime = fileCommits.LastOrDefault()?.Commit.Author.Date.DateTime ?? DateTime.MinValue; + + var lastSignificantUpdateTime = !isNavigationDocument && !isParameterDocument && version == project.LatestVersionBranchName ? + await GetLastSignificantUpdateTime( + fileCommits, + project, + project.GetGitHubInnerUrl(languageCode, documentName), + lastKnownSignificantUpdateTime, + documentCreationTime + ) ?? lastKnownSignificantUpdateTime + : null; - var document= new Document(GuidGenerator.Create(), - project.Id, - documentName, - version, + var document = new Document(GuidGenerator.Create(), + project.Id, + documentName, + version, languageCode, - fileName, + fileName, await DownloadWebContentAsStringAsync(rawDocumentUrl, token, userAgent), - project.Format, - editLink, + project.Format, + editLink, rootUrl, - rawRootUrl, + rawRootUrl, localDirectory, - fileCommits.LastOrDefault()?.Commit.Author.Date.DateTime ?? DateTime.MinValue, + documentCreationTime, fileCommits.FirstOrDefault()?.Commit.Author.Date.DateTime ?? DateTime.MinValue, - DateTime.Now); + DateTime.Now, + lastSignificantUpdateTime); - var authors = fileCommits + var authors = fileCommits .Where(x => x.Author != null) .Select(x => x.Author) .GroupBy(x => x.Id) @@ -82,6 +97,42 @@ namespace Volo.Docs.GitHub.Documents return document; } + private async Task GetLastSignificantUpdateTime( + IReadOnlyList fileCommits, + Project project, + string fileName, + DateTime? lastKnownSignificantUpdateTime, + DateTime documentCreationTime) + { + if (!fileCommits.Any()) + { + return null; + } + + var fileCommitsAfterCreation = fileCommits.Take(fileCommits.Count - 1); + + var commitsToEvaluate = (lastKnownSignificantUpdateTime != null + ? fileCommitsAfterCreation.Where(c => c.Commit.Author.Date.DateTime > lastKnownSignificantUpdateTime) + : fileCommitsAfterCreation).Where(c => c.Commit.Author.Date.DateTime > DateTime.Now.AddDays(-14)); + + foreach (var gitHubCommit in commitsToEvaluate) + { + + var fullCommit = await _githubRepositoryManager.GetSingleCommitsAsync( + GetOwnerNameFromUrl(project.GetGitHubUrl()), + GetRepositoryNameFromUrl(project.GetGitHubUrl()), + gitHubCommit.Sha, + project.GetGitHubAccessTokenOrNull()); + + if (_githubPatchAnalyzer.HasPatchSignificantChanges(fullCommit.Files.First(f => f.Filename == fileName).Patch)) + { + return gitHubCommit.Commit.Author.Date.DateTime; + } + } + + return null; + } + public async Task> GetVersionsAsync(Project project) { List versions; diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubPatchAnalyzer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubPatchAnalyzer.cs new file mode 100644 index 0000000000..091c2fb42f --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubPatchAnalyzer.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Volo.Abp.Domain.Services; + +namespace Volo.Docs.GitHub.Documents +{ + public class GithubPatchAnalyzer : DomainService, IGithubPatchAnalyzer + { + public bool HasPatchSignificantChanges(string patch) + { + var changes = GetChanges(patch); + + return IsChangesSignificant(changes); + } + + + private bool IsChangesSignificant(CommitChanges change) + { + if (CompareLineCount(change)) + { + return true; + } + + if (CompareWordCount(change)) + { + return true; + } + + if (CompareWords(change)) + { + return true; + } + + return false; + } + + private static bool CompareLineCount(CommitChanges change) + { + return Math.Abs(change.NewLines.Count - change.OldLines.Count) >= 3; + } + + private static bool CompareWordCount(CommitChanges change) + { + var wordCountInNewLines = + string.Join(" ", change.NewLines).Split(" ").Count(s => !string.IsNullOrWhiteSpace(s)); + var wordCountInOldLines = + string.Join(" ", change.OldLines).Split(" ").Count(s => !string.IsNullOrWhiteSpace(s)); + + return Math.Abs(wordCountInNewLines - wordCountInOldLines) >= 15; + } + + private bool CompareWords(CommitChanges change) + { + var wordsInNewLines = GetDistinctWordsFromLineList(change.NewLines); + var wordsInOldLines = GetDistinctWordsFromLineList(change.OldLines); + + var differentWordsInNewLines = wordsInNewLines.Except(wordsInOldLines).Count(); + var differentWordsInOldLines = wordsInOldLines.Except(wordsInNewLines).Count(); + + return differentWordsInNewLines + differentWordsInOldLines >= 10; + } + + private CommitChanges GetChanges(string patch) + { + var changes = new List(); + var pathSplited = patch.Split("@@"); + var changeList = pathSplited.Where(s => !string.IsNullOrWhiteSpace(s)).Where((c, i) => i % 2 == 1).ToList(); + + foreach (var change in changeList) + { + var commitChange = new CommitChanges(); + var lines = change.Split("\n"); + + commitChange.OldLines.AddRange(lines.Where(l => l.StartsWith("-")).Select(l => l.Substring(1)).Where(l => !string.IsNullOrWhiteSpace(l))); + commitChange.NewLines.AddRange(lines.Where(l => l.StartsWith("+")).Select(l => l.Substring(1)).Where(l => !string.IsNullOrWhiteSpace(l))); + + changes.Add(commitChange); + } + + return MergeChanges(changes); + } + private CommitChanges MergeChanges(List changes) + { + var mergedChanges = new CommitChanges(); + + foreach (var commitChanges in changes) + { + mergedChanges.NewLines.AddRange(commitChanges.NewLines); + mergedChanges.OldLines.AddRange(commitChanges.OldLines); + } + + return mergedChanges; + } + + private List GetDistinctWordsFromLineList(List lines) + { + return string.Join(" ", lines).Split(" ").Where(s => !string.IsNullOrWhiteSpace(s)) + .Select(TrimAndRemovePunctuation).Distinct().ToList(); + } + + private string TrimAndRemovePunctuation(string str) + { + return new string(str.Trim().ToCharArray().Where(c => !char.IsPunctuation(c)).ToArray()); + } + + private class CommitChanges + { + public List OldLines { get; set; } + + public List NewLines { get; set; } + + public CommitChanges() + { + OldLines = new List(); + NewLines = new List(); + } + } + } +} diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubRepositoryManager.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubRepositoryManager.cs index 787dcbba48..4627800832 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubRepositoryManager.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubRepositoryManager.cs @@ -75,5 +75,15 @@ namespace Volo.Docs.GitHub.Documents var request = new CommitRequest { Path = filename, Sha = version }; return await client.Repository.Commit.GetAll(repo.Id, request); } + + public async Task GetSingleCommitsAsync(string name, string repositoryName, string sha, string token) + { + var client = token.IsNullOrWhiteSpace() + ? new GitHubClient(new ProductHeaderValue(name)) + : new GitHubClient(new ProductHeaderValue(name), new InMemoryCredentialStore(new Credentials(token))); + + var repo = await client.Repository.Get(name, repositoryName); + return await client.Repository.Commit.Get(repo.Id, sha); + } } } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/IGithubPatchAnalyzer.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/IGithubPatchAnalyzer.cs new file mode 100644 index 0000000000..da57fe4c9f --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/IGithubPatchAnalyzer.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Volo.Abp.Domain.Services; + +namespace Volo.Docs.GitHub.Documents +{ + public interface IGithubPatchAnalyzer : IDomainService + { + bool HasPatchSignificantChanges(string patch); + } +} diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/IGithubRepositoryManager.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/IGithubRepositoryManager.cs index fa81ba695b..67536fc559 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/IGithubRepositoryManager.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/IGithubRepositoryManager.cs @@ -16,5 +16,7 @@ namespace Volo.Docs.GitHub.Documents Task> GetReleasesAsync(string name, string repositoryName, string token); Task> GetFileCommitsAsync(string name, string repositoryName, string version, string filename, string token); + + Task GetSingleCommitsAsync(string name, string repositoryName, string sha, string token); } } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Projects/ProjectGithubExtensions.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Projects/ProjectGithubExtensions.cs index d518132950..4810f94ac4 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Projects/ProjectGithubExtensions.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Projects/ProjectGithubExtensions.cs @@ -14,6 +14,12 @@ namespace Volo.Docs.GitHub.Projects return project.ExtraProperties["GitHubRootUrl"] as string; } + public static string GetGitHubInnerUrl([NotNull] this Project project, string languageCode, string documentName) + { + return project + .GetGitHubUrl().Split("{version}")[1].EnsureEndsWith('/').TrimStart('/') + languageCode + '/' + documentName; + } + public static string GetGitHubUrl([NotNull] this Project project, string version) { return project diff --git a/modules/docs/src/Volo.Docs.Web/Areas/Documents/TagHelpers/TreeTagHelper.cs b/modules/docs/src/Volo.Docs.Web/Areas/Documents/TagHelpers/TreeTagHelper.cs index 1c57191d0a..5f7ae8e7a7 100644 --- a/modules/docs/src/Volo.Docs.Web/Areas/Documents/TagHelpers/TreeTagHelper.cs +++ b/modules/docs/src/Volo.Docs.Web/Areas/Documents/TagHelpers/TreeTagHelper.cs @@ -127,16 +127,16 @@ namespace Volo.Docs.Areas.Documents.TagHelpers if (!node.Path.IsNullOrWhiteSpace() && node.CreationTime.HasValue && node.LastUpdatedTime.HasValue) { - var newBadge = "" + _localizer["New"] + ""; - var updBadge = "" + _localizer["Upd"] + ""; - if(node.CreationTime + TimeSpan.FromDays(14) > DateTime.Now) { - badge = newBadge; + var newBadge = "" + _localizer["New"] + ""; + badge += newBadge; } - else if (node.LastUpdatedTime + TimeSpan.FromDays(14) > DateTime.Now) + + if (node.LastSignificantUpdateTime != null && node.LastSignificantUpdateTime + TimeSpan.FromDays(14) > DateTime.Now) { - badge = updBadge; + var updBadge = "" + _localizer["Upd"] + ""; + badge += updBadge; } }