package handler import ( "database/sql" "errors" "git.dmitriygnatenko.ru/dima/go-common/logger" "github.com/gofiber/fiber/v2" "git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/dto" "git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/mapper" "git.dmitriygnatenko.ru/dima/dmitriygnatenko-v2/internal/services/i18n" ) const ( ArticleCacheKey = "article" RecentArticlesCacheKey = "recent-articles" UsedTagsCacheKey = "used-tags" previewArticlesCount = 3 articleParam = "article" ) func ArticleHandler( cacheService CacheService, articleRepository ArticleRepository, tagRepository TagRepository, ) fiber.Handler { return func(fctx *fiber.Ctx) error { var renderData fiber.Map ctx := fctx.Context() url := fctx.Params(articleParam) lang := mapper.LanguageFromContext(fctx) // article articleCacheKey := ArticleCacheKey + url cacheData, found := cacheService.Get(articleCacheKey) if found { if articleData, ok := cacheData.(fiber.Map); ok { renderData = articleData } } if renderData == nil { article, err := articleRepository.GetByURL(ctx, url, mapper.ToLanguageModel(lang)) if err != nil { logger.Error(ctx, err.Error()) if errors.Is(err, sql.ErrNoRows) { return fiber.ErrNotFound } logger.Error(ctx, err.Error()) return err } if !article.IsActive { return fiber.ErrNotFound } articleDTO := mapper.ToArticle(lang, *article) renderData = fiber.Map{ "lang": lang, "headTitle": i18n.T(lang, "head_title"), "headDescription": articleDTO.MetaDescription, "headKeywords": articleDTO.MetaKeywords, "pageTitle": i18n.T(lang, "article_page_title", articleDTO.Title), "article": articleDTO, } cacheService.Set(articleCacheKey, renderData, nil) } // recent articles recentArticlesCacheKey := RecentArticlesCacheKey + string(lang) cacheData, found = cacheService.Get(recentArticlesCacheKey) if found { if articlesData, ok := cacheData.([]dto.ArticlePreview); ok { renderData["sidebarArticles"] = articlesData } } if _, ok := renderData["sidebarArticles"]; !ok { articles, err := articleRepository.GetAllPreview(ctx, mapper.ToLanguageModel(lang)) if err != nil { logger.Error(ctx, err.Error()) return err } if len(articles) > previewArticlesCount { articles = articles[:previewArticlesCount] } sidebarArticles := mapper.ToArticlesPreview(lang, articles) renderData["sidebarArticles"] = sidebarArticles cacheService.Set(recentArticlesCacheKey, sidebarArticles, nil) } // tags usedTagsCacheKey := UsedTagsCacheKey + string(lang) cacheData, found = cacheService.Get(usedTagsCacheKey) if found { if tagsData, ok := cacheData.([]dto.Tag); ok { renderData["sidebarTags"] = tagsData } } if _, ok := renderData["sidebarTags"]; !ok { tags, err := tagRepository.GetAllUsed(ctx, mapper.ToLanguageModel(lang)) if err != nil { logger.Error(ctx, err.Error()) return err } sidebarTags := mapper.ToTagsList(tags) renderData["sidebarTags"] = sidebarTags cacheService.Set(usedTagsCacheKey, sidebarTags, nil) } return fctx.Render("article", renderData, "_layout") } }