public async Task <Tag> Create(string name) { if (!ValidateTagName(name)) { return(null); } var normalizedName = NormalizeTagName(name, _tagNormalization.Value); if (_tagRepo.Any(t => t.NormalizedName == normalizedName)) { return(Get(normalizedName)); } var newTag = new TagEntity { DisplayName = name, NormalizedName = normalizedName }; var tag = await _tagRepo.AddAsync(newTag); await _audit.AddAuditEntry(EventType.Content, AuditEventId.TagCreated, $"Tag '{tag.NormalizedName}' created."); return(new() { DisplayName = newTag.DisplayName, NormalizedName = newTag.NormalizedName }); }
public async Task <Guid> CreateAsync(string username, string clearPassword) { if (string.IsNullOrWhiteSpace(username)) { throw new ArgumentNullException(nameof(username), "value must not be empty."); } if (string.IsNullOrWhiteSpace(clearPassword)) { throw new ArgumentNullException(nameof(clearPassword), "value must not be empty."); } var uid = Guid.NewGuid(); var account = new LocalAccountEntity { Id = uid, CreateTimeUtc = DateTime.UtcNow, Username = username.ToLower().Trim(), PasswordHash = HashPassword(clearPassword.Trim()) }; await _accountRepo.AddAsync(account); await _audit.AddAuditEntry(EventType.Settings, AuditEventId.SettingsAccountCreated, $"Account '{account.Id}' created."); return(uid); }
public async Task <IActionResult> Index() { if (_authenticationSettings.Provider == AuthenticationProvider.AzureAD) { await _blogAudit.AddAuditEntry(EventType.Authentication, AuditEventId.LoginSuccessAAD, $"Authentication success for Azure account '{User.Identity?.Name}'"); } return(RedirectToAction("Index", "PostManage")); }
public async Task <IActionResult> SignIn(SignInViewModel model) { try { if (ModelState.IsValid) { var uid = await _localAccountService.ValidateAsync(model.Username, model.Password); if (uid != Guid.Empty) { var claims = new List <Claim> { new (ClaimTypes.Name, model.Username), new (ClaimTypes.Role, "Administrator"), new ("uid", uid.ToString()) }; var ci = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); var p = new ClaimsPrincipal(ci); await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, p); await _localAccountService.LogSuccessLoginAsync(uid, HttpContext.Connection.RemoteIpAddress?.ToString()); var successMessage = $@"Authentication success for local account ""{model.Username}"""; _logger.LogInformation(successMessage); await _blogAudit.AddAuditEntry(EventType.Authentication, AuditEventId.LoginSuccessLocal, successMessage); return(RedirectToAction("Index", "Admin")); } ModelState.AddModelError(string.Empty, "Invalid Login Attempt."); return(View(model)); } var failMessage = $@"Authentication failed for local account ""{model.Username}"""; _logger.LogWarning(failMessage); await _blogAudit.AddAuditEntry(EventType.Authentication, AuditEventId.LoginFailedLocal, failMessage); Response.StatusCode = StatusCodes.Status400BadRequest; ModelState.AddModelError(string.Empty, "Bad Request."); return(View(model)); } catch (Exception e) { _logger.LogWarning($@"Authentication failed for local account ""{model.Username}"""); ModelState.AddModelError(string.Empty, e.Message); return(View(model)); } }
public async Task UpdateAsync(int tagId, string newName) { var tag = await _tagRepo.GetAsync(tagId); if (null == tag) { return; } tag.DisplayName = newName; tag.NormalizedName = NormalizeTagName(newName, _tagNormalization.Value); await _tagRepo.UpdateAsync(tag); await _audit.AddAuditEntry(EventType.Content, AuditEventId.TagUpdated, $"Tag id '{tagId}' is updated."); }
public async Task UpdateAsync(int tagId, string newName) { Logger.LogInformation($"Updating tag {tagId} with new name {newName}"); var tag = await _tagRepository.GetAsync(tagId); if (null == tag) { return; } tag.DisplayName = newName; tag.NormalizedName = NormalizeTagName(newName); await _tagRepository.UpdateAsync(tag); await _blogAudit.AddAuditEntry(EventType.Content, AuditEventId.TagUpdated, $"Tag id '{tagId}' is updated."); }
public async Task <IActionResult> Delete(Guid pingbackId, [FromServices] IBlogAudit blogAudit) { await _pingbackService.DeletePingbackHistory(pingbackId); await blogAudit.AddAuditEntry(EventType.Content, AuditEventId.PingbackDeleted, $"Pingback '{pingbackId}' deleted."); return(Ok()); }
public async Task AddAsync(string title, string linkUrl) { if (!Uri.IsWellFormedUriString(linkUrl, UriKind.Absolute)) { throw new InvalidOperationException($"{nameof(linkUrl)} is not a valid url."); } var fdLink = new FriendLinkEntity { Id = Guid.NewGuid(), LinkUrl = linkUrl, Title = title }; await _friendlinkRepository.AddAsync(fdLink); await _blogAudit.AddAuditEntry(EventType.Settings, AuditEventId.SettingsSavedFriendLink, "FriendLink Settings updated."); }
public async Task <Guid> CreateAsync(CreateMenuRequest request) { var uid = Guid.NewGuid(); var menu = new MenuEntity { Id = uid, Title = request.Title.Trim(), DisplayOrder = request.DisplayOrder, Icon = request.Icon, Url = request.Url, IsOpenInNewTab = request.IsOpenInNewTab }; await _menuRepository.AddAsync(menu); await _blogAudit.AddAuditEntry(EventType.Content, AuditEventId.MenuCreated, $"Menu '{menu.Id}' created."); return(uid); }
public async Task ToggleApprovalAsync(Guid[] commentIds) { if (commentIds is null || !commentIds.Any()) { throw new ArgumentNullException(nameof(commentIds)); } var spec = new CommentSpec(commentIds); var comments = await _commentRepo.GetAsync(spec); foreach (var cmt in comments) { cmt.IsApproved = !cmt.IsApproved; await _commentRepo.UpdateAsync(cmt); string logMessage = $"Updated comment approval status to '{cmt.IsApproved}' for comment id: '{cmt.Id}'"; await _audit.AddAuditEntry( EventType.Content, cmt.IsApproved?AuditEventId.CommentApproval : AuditEventId.CommentDisapproval, logMessage); } }
public async Task <Guid> CreateAsync(UpdatePageRequest request) { var uid = Guid.NewGuid(); var page = new PageEntity { Id = uid, Title = request.Title.Trim(), Slug = request.Slug.ToLower().Trim(), MetaDescription = request.MetaDescription, CreateTimeUtc = DateTime.UtcNow, HtmlContent = request.HtmlContent, CssContent = request.CssContent, HideSidebar = request.HideSidebar, IsPublished = request.IsPublished }; await _pageRepo.AddAsync(page); await _audit.AddAuditEntry(EventType.Content, AuditEventId.PageCreated, $"Page '{page.Id}' created."); return(uid); }
public async Task CreateAsync(CreateCategoryRequest createCategoryRequest) { var exists = _categoryRepository.Any(c => c.RouteName == createCategoryRequest.RouteName); if (exists) { return; } var category = new CategoryEntity { Id = Guid.NewGuid(), RouteName = createCategoryRequest.RouteName.Trim(), Note = createCategoryRequest.Note.Trim(), DisplayName = createCategoryRequest.DisplayName.Trim() }; await _categoryRepository.AddAsync(category); _cache.Remove(CacheDivision.General, "allcats"); await _blogAudit.AddAuditEntry(EventType.Content, AuditEventId.CategoryCreated, $"Category '{category.RouteName}' created"); }
public async Task <IActionResult> General(GeneralSettingsViewModel model, [FromServices] ITZoneResolver tZoneResolver) { if (!ModelState.IsValid) { return(BadRequest(ModelState)); } _blogConfig.GeneralSettings.MetaKeyword = model.MetaKeyword; _blogConfig.GeneralSettings.MetaDescription = model.MetaDescription; _blogConfig.GeneralSettings.CanonicalPrefix = model.CanonicalPrefix; _blogConfig.GeneralSettings.SiteTitle = model.SiteTitle; _blogConfig.GeneralSettings.Copyright = model.Copyright; _blogConfig.GeneralSettings.LogoText = model.LogoText; _blogConfig.GeneralSettings.SideBarCustomizedHtmlPitch = model.SideBarCustomizedHtmlPitch; _blogConfig.GeneralSettings.SideBarOption = Enum.Parse <SideBarOption>(model.SideBarOption); _blogConfig.GeneralSettings.FooterCustomizedHtmlPitch = model.FooterCustomizedHtmlPitch; _blogConfig.GeneralSettings.TimeZoneUtcOffset = tZoneResolver.GetTimeSpanByZoneId(model.SelectedTimeZoneId).ToString(); _blogConfig.GeneralSettings.TimeZoneId = model.SelectedTimeZoneId; _blogConfig.GeneralSettings.ThemeFileName = model.SelectedThemeFileName; _blogConfig.GeneralSettings.OwnerName = model.OwnerName; _blogConfig.GeneralSettings.OwnerEmail = model.OwnerEmail; _blogConfig.GeneralSettings.Description = model.OwnerDescription; _blogConfig.GeneralSettings.ShortDescription = model.OwnerShortDescription; _blogConfig.GeneralSettings.AutoDarkLightTheme = model.AutoDarkLightTheme; await _blogConfig.SaveAsync(_blogConfig.GeneralSettings); AppDomain.CurrentDomain.SetData("CurrentThemeColor", null); await _blogAudit.AddAuditEntry(EventType.Settings, AuditEventId.SettingsSavedGeneral, "General Settings updated."); return(Ok()); }
public async Task <PostEntity> CreateAsync(CreatePostRequest request) { var abs = GetPostAbstract( request.EditorContent, AppSettings.PostAbstractWords, AppSettings.Editor == EditorChoice.Markdown); var post = new PostEntity { CommentEnabled = request.EnableComment, Id = Guid.NewGuid(), PostContent = request.EditorContent, ContentAbstract = abs, CreateOnUtc = DateTime.UtcNow, Slug = request.Slug.ToLower().Trim(), Title = request.Title.Trim(), ContentLanguageCode = request.ContentLanguageCode, ExposedToSiteMap = request.ExposedToSiteMap, IsFeedIncluded = request.IsFeedIncluded, PubDateUtc = request.IsPublished ? DateTime.UtcNow : (DateTime?)null, IsDeleted = false, IsPublished = request.IsPublished, PostExtension = new PostExtensionEntity { Hits = 0, Likes = 0 } }; // check if exist same slug under the same day // linq to sql fix: // cannot write "p.PubDateUtc.GetValueOrDefault().Date == DateTime.UtcNow.Date" // it will not blow up, but can result in select ENTIRE posts and evaluated in memory!!! // - The LINQ expression 'where (Convert([p]?.PubDateUtc?.GetValueOrDefault(), DateTime).Date == DateTime.UtcNow.Date)' could not be translated and will be evaluated locally // Why EF Core this diao yang? if (_postRepository.Any(p => p.Slug == post.Slug && p.PubDateUtc != null && p.PubDateUtc.Value.Year == DateTime.UtcNow.Date.Year && p.PubDateUtc.Value.Month == DateTime.UtcNow.Date.Month && p.PubDateUtc.Value.Day == DateTime.UtcNow.Date.Day)) { var uid = Guid.NewGuid(); post.Slug += $"-{uid.ToString().ToLower().Substring(0, 8)}"; Logger.LogInformation($"Found conflict for post slug, generated new slug: {post.Slug}"); } // add categories if (null != request.CategoryIds && request.CategoryIds.Length > 0) { foreach (var cid in request.CategoryIds) { if (_categoryRepository.Any(c => c.Id == cid)) { post.PostCategory.Add(new PostCategoryEntity { CategoryId = cid, PostId = post.Id }); } } } // add tags if (null != request.Tags && request.Tags.Length > 0) { foreach (var item in request.Tags) { if (!TagService.ValidateTagName(item)) { continue; } var tag = await _tagRepository.GetAsync(q => q.DisplayName == item); if (null == tag) { var newTag = new TagEntity { DisplayName = item, NormalizedName = TagService.NormalizeTagName(item) }; tag = await _tagRepository.AddAsync(newTag); await _blogAudit.AddAuditEntry(EventType.Content, AuditEventId.TagCreated, $"Tag '{tag.NormalizedName}' created."); } post.PostTag.Add(new PostTagEntity { TagId = tag.Id, PostId = post.Id }); } } await _postRepository.AddAsync(post); await _blogAudit.AddAuditEntry(EventType.Content, AuditEventId.PostCreated, $"Post created, id: {post.Id}"); return(post); }