| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package controller |
| |
| import ( |
| "encoding/json" |
| "fmt" |
| "html/template" |
| "net/http" |
| "net/url" |
| "regexp" |
| "strings" |
| "time" |
| |
| "github.com/apache/answer/internal/base/middleware" |
| "github.com/apache/answer/internal/base/pager" |
| "github.com/apache/answer/internal/service/content" |
| "github.com/apache/answer/internal/service/event_queue" |
| "github.com/apache/answer/plugin" |
| |
| "github.com/apache/answer/internal/base/constant" |
| "github.com/apache/answer/internal/base/handler" |
| "github.com/apache/answer/internal/base/translator" |
| templaterender "github.com/apache/answer/internal/controller/template_render" |
| "github.com/apache/answer/internal/entity" |
| "github.com/apache/answer/internal/schema" |
| "github.com/apache/answer/internal/service/siteinfo_common" |
| "github.com/apache/answer/pkg/checker" |
| "github.com/apache/answer/pkg/converter" |
| "github.com/apache/answer/pkg/htmltext" |
| "github.com/apache/answer/pkg/obj" |
| "github.com/apache/answer/pkg/uid" |
| "github.com/apache/answer/ui" |
| "github.com/gin-gonic/gin" |
| "github.com/segmentfault/pacman/log" |
| ) |
| |
| var SiteUrl = "" |
| |
| type TemplateController struct { |
| scriptPath []string |
| cssPath string |
| templateRenderController *templaterender.TemplateRenderController |
| siteInfoService siteinfo_common.SiteInfoCommonService |
| eventQueueService event_queue.EventQueueService |
| userService *content.UserService |
| questionService *content.QuestionService |
| } |
| |
| // NewTemplateController new controller |
| func NewTemplateController( |
| templateRenderController *templaterender.TemplateRenderController, |
| siteInfoService siteinfo_common.SiteInfoCommonService, |
| eventQueueService event_queue.EventQueueService, |
| userService *content.UserService, |
| questionService *content.QuestionService, |
| ) *TemplateController { |
| script, css := GetStyle() |
| return &TemplateController{ |
| scriptPath: script, |
| cssPath: css, |
| templateRenderController: templateRenderController, |
| siteInfoService: siteInfoService, |
| eventQueueService: eventQueueService, |
| userService: userService, |
| questionService: questionService, |
| } |
| } |
| func GetStyle() (script []string, css string) { |
| file, err := ui.Build.ReadFile("build/index.html") |
| if err != nil { |
| return |
| } |
| scriptRegexp := regexp.MustCompile(`<script defer="defer" src="([^"]*)"></script>`) |
| scriptData := scriptRegexp.FindAllStringSubmatch(string(file), -1) |
| for _, s := range scriptData { |
| if len(s) == 2 { |
| script = append(script, s[1]) |
| } |
| } |
| |
| cssRegexp := regexp.MustCompile(`<link href="(.*)" rel="stylesheet">`) |
| cssListData := cssRegexp.FindStringSubmatch(string(file)) |
| if len(cssListData) == 2 { |
| css = cssListData[1] |
| } |
| return |
| } |
| func (tc *TemplateController) SiteInfo(ctx *gin.Context) *schema.TemplateSiteInfoResp { |
| var err error |
| resp := &schema.TemplateSiteInfoResp{} |
| resp.General, err = tc.siteInfoService.GetSiteGeneral(ctx) |
| if err != nil { |
| log.Error(err) |
| } |
| SiteUrl = resp.General.SiteUrl |
| resp.Interface, err = tc.siteInfoService.GetSiteInterface(ctx) |
| if err != nil { |
| log.Error(err) |
| } |
| |
| resp.Branding, err = tc.siteInfoService.GetSiteBranding(ctx) |
| if err != nil { |
| log.Error(err) |
| } |
| |
| resp.SiteSeo, err = tc.siteInfoService.GetSiteSeo(ctx) |
| if err != nil { |
| log.Error(err) |
| } |
| |
| resp.CustomCssHtml, err = tc.siteInfoService.GetSiteCustomCssHTML(ctx) |
| if err != nil { |
| log.Error(err) |
| } |
| resp.Year = fmt.Sprintf("%d", time.Now().Year()) |
| return resp |
| } |
| |
| // Index question list |
| func (tc *TemplateController) Index(ctx *gin.Context) { |
| req := &schema.QuestionPageReq{ |
| OrderCond: "newest", |
| } |
| if handler.BindAndCheck(ctx, req) { |
| return |
| } |
| |
| var page = req.Page |
| |
| data, count, err := tc.templateRenderController.Index(ctx, req) |
| if err != nil || (len(data) == 0 && pager.ValPageOutOfRange(count, page, req.PageSize)) { |
| tc.Page404(ctx) |
| return |
| } |
| |
| hotQuestionReq := &schema.QuestionPageReq{ |
| Page: 1, |
| PageSize: 6, |
| OrderCond: "hot", |
| InDays: 7, |
| } |
| hotQuestion, _, _ := tc.templateRenderController.Index(ctx, hotQuestionReq) |
| |
| siteInfo := tc.SiteInfo(ctx) |
| siteInfo.Canonical = siteInfo.General.SiteUrl |
| |
| UrlUseTitle := false |
| if siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitle || |
| siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitleByShortID { |
| UrlUseTitle = true |
| } |
| siteInfo.Title = "" |
| tc.html(ctx, http.StatusOK, "question.html", siteInfo, gin.H{ |
| "data": data, |
| "useTitle": UrlUseTitle, |
| "page": templaterender.Paginator(page, req.PageSize, count), |
| "path": "questions", |
| "hotQuestion": hotQuestion, |
| }) |
| } |
| |
| func (tc *TemplateController) QuestionList(ctx *gin.Context) { |
| req := &schema.QuestionPageReq{ |
| OrderCond: "newest", |
| } |
| if handler.BindAndCheck(ctx, req) { |
| return |
| } |
| var page = req.Page |
| data, count, err := tc.templateRenderController.Index(ctx, req) |
| if err != nil || (len(data) == 0 && pager.ValPageOutOfRange(count, page, req.PageSize)) { |
| tc.Page404(ctx) |
| return |
| } |
| |
| hotQuestionReq := &schema.QuestionPageReq{ |
| Page: 1, |
| PageSize: 6, |
| OrderCond: "hot", |
| InDays: 7, |
| } |
| hotQuestion, _, _ := tc.templateRenderController.Index(ctx, hotQuestionReq) |
| |
| siteInfo := tc.SiteInfo(ctx) |
| siteInfo.Canonical = fmt.Sprintf("%s/questions", siteInfo.General.SiteUrl) |
| if page > 1 { |
| siteInfo.Canonical = fmt.Sprintf("%s/questions?page=%d", siteInfo.General.SiteUrl, page) |
| } |
| |
| UrlUseTitle := false |
| if siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitle || |
| siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitleByShortID { |
| UrlUseTitle = true |
| } |
| siteInfo.Title = fmt.Sprintf("%s - %s", translator.Tr(handler.GetLang(ctx), constant.QuestionsTitleTrKey), siteInfo.General.Name) |
| tc.html(ctx, http.StatusOK, "question.html", siteInfo, gin.H{ |
| "data": data, |
| "useTitle": UrlUseTitle, |
| "page": templaterender.Paginator(page, req.PageSize, count), |
| "hotQuestion": hotQuestion, |
| }) |
| } |
| |
| func (tc *TemplateController) QuestionInfoRedirect(ctx *gin.Context, siteInfo *schema.TemplateSiteInfoResp, correctTitle bool) (jump bool, url string) { |
| questionID := ctx.Param("id") |
| title := ctx.Param("title") |
| answerID := uid.DeShortID(title) |
| titleIsAnswerID := false |
| needChangeShortID := false |
| |
| objectType, err := obj.GetObjectTypeStrByObjectID(answerID) |
| if err == nil && objectType == constant.AnswerObjectType { |
| titleIsAnswerID = true |
| } |
| |
| siteSeo, err := tc.siteInfoService.GetSiteSeo(ctx) |
| if err != nil { |
| return false, "" |
| } |
| isShortID := uid.IsShortID(questionID) |
| if siteSeo.IsShortLink() { |
| if !isShortID { |
| questionID = uid.EnShortID(questionID) |
| needChangeShortID = true |
| } |
| if titleIsAnswerID { |
| answerID = uid.EnShortID(answerID) |
| } |
| } else { |
| if isShortID { |
| needChangeShortID = true |
| questionID = uid.DeShortID(questionID) |
| } |
| if titleIsAnswerID { |
| answerID = uid.DeShortID(answerID) |
| } |
| } |
| |
| if _, err := tc.templateRenderController.AnswerDetail(ctx, answerID); err != nil { |
| answerID = "" |
| titleIsAnswerID = false |
| } |
| |
| url = fmt.Sprintf("%s/questions/%s", siteInfo.General.SiteUrl, questionID) |
| if siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionID || siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDByShortID { |
| if len(ctx.Request.URL.Query()) > 0 { |
| url = fmt.Sprintf("%s?%s", url, ctx.Request.URL.RawQuery) |
| } |
| if needChangeShortID { |
| return true, url |
| } |
| //not have title |
| if titleIsAnswerID || len(title) == 0 { |
| return false, "" |
| } |
| |
| return true, url |
| } else { |
| |
| detail, err := tc.templateRenderController.QuestionDetail(ctx, questionID) |
| if err != nil { |
| tc.Page404(ctx) |
| return |
| } |
| url = fmt.Sprintf("%s/%s", url, htmltext.UrlTitle(detail.Title)) |
| if titleIsAnswerID { |
| url = fmt.Sprintf("%s/%s", url, answerID) |
| } |
| |
| if len(ctx.Request.URL.Query()) > 0 { |
| url = fmt.Sprintf("%s?%s", url, ctx.Request.URL.RawQuery) |
| } |
| //have title |
| if len(title) > 0 && !titleIsAnswerID && correctTitle { |
| if needChangeShortID { |
| return true, url |
| } |
| return false, "" |
| } |
| return true, url |
| } |
| } |
| |
| // QuestionInfo question and answers info |
| func (tc *TemplateController) QuestionInfo(ctx *gin.Context) { |
| id := ctx.Param("id") |
| title := ctx.Param("title") |
| answerid := ctx.Param("answerid") |
| shareUsername := ctx.Query("share") |
| if checker.IsQuestionsIgnorePath(id) { |
| // if id == "ask" { |
| file, err := ui.Build.ReadFile("build/index.html") |
| if err != nil { |
| log.Error(err) |
| tc.Page404(ctx) |
| return |
| } |
| ctx.Header("content-type", "text/html;charset=utf-8") |
| ctx.String(http.StatusOK, string(file)) |
| return |
| } |
| |
| correctTitle := false |
| |
| detail, err := tc.templateRenderController.QuestionDetail(ctx, id) |
| if err != nil { |
| tc.Page404(ctx) |
| return |
| } |
| if len(shareUsername) > 0 { |
| userInfo, err := tc.userService.GetOtherUserInfoByUsername( |
| ctx, &schema.GetOtherUserInfoByUsernameReq{Username: shareUsername}) |
| if err == nil { |
| tc.eventQueueService.Send(ctx, schema.NewEvent(constant.EventUserShare, userInfo.ID). |
| QID(id, detail.UserID).AID(answerid, "")) |
| } |
| } |
| encodeTitle := htmltext.UrlTitle(detail.Title) |
| if encodeTitle == title { |
| correctTitle = true |
| } |
| |
| siteInfo := tc.SiteInfo(ctx) |
| jump, jumpurl := tc.QuestionInfoRedirect(ctx, siteInfo, correctTitle) |
| if jump { |
| ctx.Redirect(http.StatusFound, jumpurl) |
| return |
| } |
| |
| // answers |
| answerReq := &schema.AnswerListReq{ |
| QuestionID: id, |
| Order: "", |
| Page: 1, |
| PageSize: 999, |
| UserID: "", |
| } |
| answers, answerCount, err := tc.templateRenderController.AnswerList(ctx, answerReq) |
| if err != nil { |
| tc.Page404(ctx) |
| return |
| } |
| |
| // comments |
| objectIDs := []string{uid.DeShortID(id)} |
| for _, answer := range answers { |
| answerID := uid.DeShortID(answer.ID) |
| objectIDs = append(objectIDs, answerID) |
| } |
| comments, err := tc.templateRenderController.CommentList(ctx, objectIDs) |
| if err != nil { |
| tc.Page404(ctx) |
| return |
| } |
| |
| UrlUseTitle := false |
| if siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitle || |
| siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitleByShortID { |
| UrlUseTitle = true |
| } |
| |
| //related question |
| userID := middleware.GetLoginUserIDFromContext(ctx) |
| relatedQuestion, _, _ := tc.questionService.SimilarQuestion(ctx, id, userID) |
| |
| siteInfo.Canonical = fmt.Sprintf("%s/questions/%s/%s", siteInfo.General.SiteUrl, id, encodeTitle) |
| if siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionID || siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDByShortID { |
| siteInfo.Canonical = fmt.Sprintf("%s/questions/%s", siteInfo.General.SiteUrl, id) |
| } |
| jsonLD := &schema.QAPageJsonLD{} |
| jsonLD.Context = "https://schema.org" |
| jsonLD.Type = "QAPage" |
| jsonLD.MainEntity.Type = "Question" |
| jsonLD.MainEntity.Name = detail.Title |
| jsonLD.MainEntity.Text = detail.HTML |
| jsonLD.MainEntity.AnswerCount = int(answerCount) |
| jsonLD.MainEntity.UpvoteCount = detail.VoteCount |
| jsonLD.MainEntity.DateCreated = time.Unix(detail.CreateTime, 0) |
| jsonLD.MainEntity.Author.Type = "Person" |
| jsonLD.MainEntity.Author.Name = detail.UserInfo.DisplayName |
| jsonLD.MainEntity.Author.URL = fmt.Sprintf("%s/users/%s", siteInfo.General.SiteUrl, detail.UserInfo.Username) |
| answerList := make([]*schema.SuggestedAnswerItem, 0) |
| for _, answer := range answers { |
| if answer.Accepted == schema.AnswerAcceptedEnable { |
| acceptedAnswerItem := &schema.AcceptedAnswerItem{} |
| acceptedAnswerItem.Type = "Answer" |
| acceptedAnswerItem.Text = answer.HTML |
| acceptedAnswerItem.DateCreated = time.Unix(answer.CreateTime, 0) |
| acceptedAnswerItem.UpvoteCount = answer.VoteCount |
| acceptedAnswerItem.URL = fmt.Sprintf("%s/%s", siteInfo.Canonical, answer.ID) |
| acceptedAnswerItem.Author.Type = "Person" |
| acceptedAnswerItem.Author.Name = answer.UserInfo.DisplayName |
| acceptedAnswerItem.Author.URL = fmt.Sprintf("%s/users/%s", siteInfo.General.SiteUrl, answer.UserInfo.Username) |
| jsonLD.MainEntity.AcceptedAnswer = acceptedAnswerItem |
| } else { |
| item := &schema.SuggestedAnswerItem{} |
| item.Type = "Answer" |
| item.Text = answer.HTML |
| item.DateCreated = time.Unix(answer.CreateTime, 0) |
| item.UpvoteCount = answer.VoteCount |
| item.URL = fmt.Sprintf("%s/%s", siteInfo.Canonical, answer.ID) |
| item.Author.Type = "Person" |
| item.Author.Name = answer.UserInfo.DisplayName |
| item.Author.URL = fmt.Sprintf("%s/users/%s", siteInfo.General.SiteUrl, answer.UserInfo.Username) |
| answerList = append(answerList, item) |
| } |
| } |
| jsonLD.MainEntity.SuggestedAnswer = answerList |
| jsonLDStr, err := json.Marshal(jsonLD) |
| if err == nil { |
| siteInfo.JsonLD = `<script data-react-helmet="true" type="application/ld+json">` + string(jsonLDStr) + ` </script>` |
| } |
| |
| siteInfo.Description = htmltext.FetchExcerpt(detail.HTML, "...", 240) |
| tags := make([]string, 0) |
| for _, tag := range detail.Tags { |
| tags = append(tags, tag.DisplayName) |
| } |
| siteInfo.Keywords = strings.Replace(strings.Trim(fmt.Sprint(tags), "[]"), " ", ",", -1) |
| siteInfo.Title = fmt.Sprintf("%s - %s", detail.Title, siteInfo.General.Name) |
| tc.html(ctx, http.StatusOK, "question-detail.html", siteInfo, gin.H{ |
| "id": id, |
| "answerid": answerid, |
| "detail": detail, |
| "answers": answers, |
| "comments": comments, |
| "noindex": detail.Show == entity.QuestionHide, |
| "useTitle": UrlUseTitle, |
| "relatedQuestion": relatedQuestion, |
| }) |
| } |
| |
| // TagList tags list |
| func (tc *TemplateController) TagList(ctx *gin.Context) { |
| req := &schema.GetTagWithPageReq{ |
| PageSize: constant.DefaultPageSize, |
| Page: 1, |
| } |
| if handler.BindAndCheck(ctx, req) { |
| return |
| } |
| data, err := tc.templateRenderController.TagList(ctx, req) |
| if err != nil || pager.ValPageOutOfRange(data.Count, req.Page, req.PageSize) { |
| tc.Page404(ctx) |
| return |
| } |
| page := templaterender.Paginator(req.Page, req.PageSize, data.Count) |
| |
| siteInfo := tc.SiteInfo(ctx) |
| siteInfo.Canonical = fmt.Sprintf("%s/tags", siteInfo.General.SiteUrl) |
| if req.Page > 1 { |
| siteInfo.Canonical = fmt.Sprintf("%s/tags?page=%d", siteInfo.General.SiteUrl, req.Page) |
| } |
| siteInfo.Title = fmt.Sprintf("%s - %s", translator.Tr(handler.GetLang(ctx), constant.TagsListTitleTrKey), siteInfo.General.Name) |
| tc.html(ctx, http.StatusOK, "tags.html", siteInfo, gin.H{ |
| "page": page, |
| "data": data, |
| }) |
| } |
| |
| // TagInfo taginfo |
| func (tc *TemplateController) TagInfo(ctx *gin.Context) { |
| tag := ctx.Param("tag") |
| req := &schema.GetTamplateTagInfoReq{} |
| if handler.BindAndCheck(ctx, req) { |
| tc.Page404(ctx) |
| return |
| } |
| nowPage := req.Page |
| req.Name = tag |
| tagInfo, questionList, questionCount, err := tc.templateRenderController.TagInfo(ctx, req) |
| if err != nil { |
| tc.Page404(ctx) |
| return |
| } |
| page := templaterender.Paginator(nowPage, req.PageSize, questionCount) |
| |
| siteInfo := tc.SiteInfo(ctx) |
| siteInfo.Canonical = fmt.Sprintf("%s/tags/%s", siteInfo.General.SiteUrl, tag) |
| if req.Page > 1 { |
| siteInfo.Canonical = fmt.Sprintf("%s/tags/%s?page=%d", siteInfo.General.SiteUrl, tag, req.Page) |
| } |
| siteInfo.Description = htmltext.FetchExcerpt(tagInfo.ParsedText, "...", 240) |
| if len(tagInfo.ParsedText) == 0 { |
| siteInfo.Description = translator.Tr(handler.GetLang(ctx), constant.TagHasNoDescription) |
| } |
| siteInfo.Keywords = tagInfo.DisplayName |
| |
| UrlUseTitle := false |
| if siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitle || |
| siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitleByShortID { |
| UrlUseTitle = true |
| } |
| siteInfo.Title = fmt.Sprintf("'%s' %s - %s", tagInfo.DisplayName, translator.Tr(handler.GetLang(ctx), constant.QuestionsTitleTrKey), siteInfo.General.Name) |
| tc.html(ctx, http.StatusOK, "tag-detail.html", siteInfo, gin.H{ |
| "tag": tagInfo, |
| "questionList": questionList, |
| "questionCount": questionCount, |
| "useTitle": UrlUseTitle, |
| "page": page, |
| }) |
| } |
| |
| // UserInfo user info |
| func (tc *TemplateController) UserInfo(ctx *gin.Context) { |
| username := ctx.Param("username") |
| if username == "" { |
| tc.Page404(ctx) |
| return |
| } |
| |
| exist := checker.IsUsersIgnorePath(username) |
| if exist { |
| file, err := ui.Build.ReadFile("build/index.html") |
| if err != nil { |
| log.Error(err) |
| tc.Page404(ctx) |
| return |
| } |
| ctx.Header("content-type", "text/html;charset=utf-8") |
| ctx.String(http.StatusOK, string(file)) |
| return |
| } |
| req := &schema.GetOtherUserInfoByUsernameReq{} |
| req.Username = username |
| userinfo, err := tc.templateRenderController.UserInfo(ctx, req) |
| if err != nil { |
| tc.Page404(ctx) |
| return |
| } |
| |
| questionList, answerList, err := tc.questionService.SearchUserTopList(ctx, req.Username, "") |
| if err != nil { |
| tc.Page404(ctx) |
| return |
| } |
| |
| siteInfo := tc.SiteInfo(ctx) |
| siteInfo.Canonical = fmt.Sprintf("%s/users/%s", siteInfo.General.SiteUrl, username) |
| siteInfo.Title = fmt.Sprintf("%s - %s", username, siteInfo.General.Name) |
| tc.html(ctx, http.StatusOK, "homepage.html", siteInfo, gin.H{ |
| "userinfo": userinfo, |
| "bio": template.HTML(userinfo.BioHTML), |
| "topQuestions": questionList, |
| "topAnswers": answerList, |
| }) |
| |
| } |
| |
| func (tc *TemplateController) Page404(ctx *gin.Context) { |
| tc.html(ctx, http.StatusNotFound, "404.html", tc.SiteInfo(ctx), gin.H{}) |
| } |
| |
| func (tc *TemplateController) html(ctx *gin.Context, code int, tpl string, siteInfo *schema.TemplateSiteInfoResp, data gin.H) { |
| var ( |
| prefix = "" |
| cssPath = "" |
| scriptPath = make([]string, len(tc.scriptPath)) |
| ) |
| |
| _ = plugin.CallCDN(func(fn plugin.CDN) error { |
| prefix = fn.GetStaticPrefix() |
| return nil |
| }) |
| |
| if prefix != "" { |
| if prefix[len(prefix)-1:] == "/" { |
| prefix = strings.TrimSuffix(prefix, "/") |
| } |
| cssPath = prefix + tc.cssPath |
| for i, path := range tc.scriptPath { |
| scriptPath[i] = prefix + path |
| } |
| } else { |
| cssPath = tc.cssPath |
| scriptPath = tc.scriptPath |
| } |
| |
| data["siteinfo"] = siteInfo |
| data["baseURL"] = "" |
| if parsedUrl, err := url.Parse(siteInfo.General.SiteUrl); err == nil { |
| data["baseURL"] = parsedUrl.Path |
| } |
| data["scriptPath"] = scriptPath |
| data["cssPath"] = cssPath |
| data["keywords"] = siteInfo.Keywords |
| if siteInfo.Description == "" { |
| siteInfo.Description = siteInfo.General.Description |
| } |
| data["title"] = siteInfo.Title |
| if siteInfo.Title == "" { |
| data["title"] = siteInfo.General.Name |
| } |
| data["description"] = siteInfo.Description |
| data["language"] = handler.GetLang(ctx) |
| data["timezone"] = siteInfo.Interface.TimeZone |
| language := strings.Replace(siteInfo.Interface.Language, "_", "-", -1) |
| data["lang"] = language |
| data["HeadCode"] = siteInfo.CustomCssHtml.CustomHead |
| data["HeaderCode"] = siteInfo.CustomCssHtml.CustomHeader |
| data["FooterCode"] = siteInfo.CustomCssHtml.CustomFooter |
| data["Version"] = constant.Version |
| data["Revision"] = constant.Revision |
| _, ok := data["path"] |
| if !ok { |
| data["path"] = "" |
| } |
| ctx.Header("X-Frame-Options", "DENY") |
| ctx.HTML(code, tpl, data) |
| } |
| |
| func (tc *TemplateController) OpenSearch(ctx *gin.Context) { |
| if tc.checkPrivateMode(ctx) { |
| tc.Page404(ctx) |
| return |
| } |
| tc.templateRenderController.OpenSearch(ctx) |
| } |
| |
| func (tc *TemplateController) Sitemap(ctx *gin.Context) { |
| if tc.checkPrivateMode(ctx) { |
| tc.Page404(ctx) |
| return |
| } |
| tc.templateRenderController.Sitemap(ctx) |
| } |
| |
| func (tc *TemplateController) SitemapPage(ctx *gin.Context) { |
| if tc.checkPrivateMode(ctx) { |
| tc.Page404(ctx) |
| return |
| } |
| page := 0 |
| pageParam := ctx.Param("page") |
| pageRegexp := regexp.MustCompile(`question-(.*).xml`) |
| pageStr := pageRegexp.FindStringSubmatch(pageParam) |
| if len(pageStr) != 2 { |
| tc.Page404(ctx) |
| return |
| } |
| page = converter.StringToInt(pageStr[1]) |
| if page == 0 { |
| tc.Page404(ctx) |
| return |
| } |
| err := tc.templateRenderController.SitemapPage(ctx, page) |
| if err != nil { |
| tc.Page404(ctx) |
| return |
| } |
| } |
| |
| func (tc *TemplateController) checkPrivateMode(ctx *gin.Context) bool { |
| resp, err := tc.siteInfoService.GetSiteLogin(ctx) |
| if err != nil { |
| log.Error(err) |
| return false |
| } |
| if resp.LoginRequired { |
| return true |
| } |
| return false |
| } |