Example #1
0
        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
            });
        }
Example #2
0
        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"));
        }
Example #4
0
        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));
            }
        }
Example #5
0
        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.");
        }
Example #6
0
        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.");
        }
Example #7
0
        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());
        }
Example #8
0
        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.");
        }
Example #9
0
        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);
        }
Example #10
0
        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);
            }
        }
Example #11
0
        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);
        }
Example #12
0
        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");
        }
Example #13
0
        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());
        }
Example #14
0
        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);
        }