mirror of https://gitee.com/answerdev/answer.git
315 lines
8.9 KiB
Go
315 lines
8.9 KiB
Go
package controller
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"html/template"
|
|
"net/http"
|
|
"regexp"
|
|
"time"
|
|
|
|
"github.com/answerdev/answer/internal/base/handler"
|
|
templaterender "github.com/answerdev/answer/internal/controller/template_render"
|
|
"github.com/answerdev/answer/internal/schema"
|
|
"github.com/answerdev/answer/internal/service/siteinfo_common"
|
|
"github.com/answerdev/answer/pkg/htmltext"
|
|
"github.com/answerdev/answer/ui"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/segmentfault/pacman/log"
|
|
)
|
|
|
|
type TemplateController struct {
|
|
scriptPath string
|
|
cssPath string
|
|
templateRenderController *templaterender.TemplateRenderController
|
|
siteInfoService *siteinfo_common.SiteInfoCommonService
|
|
}
|
|
|
|
// NewTemplateController new controller
|
|
func NewTemplateController(
|
|
templateRenderController *templaterender.TemplateRenderController,
|
|
siteInfoService *siteinfo_common.SiteInfoCommonService,
|
|
) *TemplateController {
|
|
script, css := GetStyle()
|
|
return &TemplateController{
|
|
scriptPath: script,
|
|
cssPath: css,
|
|
templateRenderController: templateRenderController,
|
|
siteInfoService: siteInfoService,
|
|
}
|
|
}
|
|
func GetStyle() (script, css string) {
|
|
file, err := ui.Build.ReadFile("build/index.html")
|
|
if err != nil {
|
|
return
|
|
}
|
|
scriptRegexp := regexp.MustCompile(`<script defer="defer" src="(.*)"></script>`)
|
|
scriptData := scriptRegexp.FindStringSubmatch(string(file))
|
|
cssRegexp := regexp.MustCompile(`<link href="(.*)" rel="stylesheet">`)
|
|
cssListData := cssRegexp.FindStringSubmatch(string(file))
|
|
if len(scriptData) == 2 {
|
|
script = scriptData[1]
|
|
}
|
|
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)
|
|
}
|
|
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.Year = fmt.Sprintf("%d", time.Now().Year())
|
|
return resp
|
|
}
|
|
|
|
// Index question list
|
|
func (tc *TemplateController) Index(ctx *gin.Context) {
|
|
req := &schema.QuestionSearch{}
|
|
if handler.BindAndCheck(ctx, req) {
|
|
tc.Page404(ctx)
|
|
return
|
|
}
|
|
|
|
var page = req.Page
|
|
|
|
data, count, err := tc.templateRenderController.Index(ctx, req)
|
|
if err != nil {
|
|
tc.Page404(ctx)
|
|
return
|
|
}
|
|
|
|
siteInfo := tc.SiteInfo(ctx)
|
|
siteInfo.Canonical = fmt.Sprintf("%s", siteInfo.General.SiteUrl)
|
|
tc.html(ctx, http.StatusOK, "question.html", siteInfo, gin.H{
|
|
"data": data,
|
|
"page": templaterender.Paginator(page, req.PageSize, count),
|
|
})
|
|
}
|
|
|
|
func (tc *TemplateController) QuestionList(ctx *gin.Context) {
|
|
req := &schema.QuestionSearch{}
|
|
if handler.BindAndCheck(ctx, req) {
|
|
tc.Page404(ctx)
|
|
return
|
|
}
|
|
var page = req.Page
|
|
data, count, err := tc.templateRenderController.Index(ctx, req)
|
|
if err != nil {
|
|
tc.Page404(ctx)
|
|
return
|
|
}
|
|
siteInfo := tc.SiteInfo(ctx)
|
|
siteInfo.Canonical = fmt.Sprintf("%s/questions", siteInfo.General.SiteUrl)
|
|
|
|
tc.html(ctx, http.StatusOK, "question.html", siteInfo, gin.H{
|
|
"data": data,
|
|
"page": templaterender.Paginator(page, req.PageSize, count),
|
|
})
|
|
}
|
|
|
|
// QuestionInfo question and answers info
|
|
func (tc *TemplateController) QuestionInfo(ctx *gin.Context) {
|
|
id := ctx.Param("id")
|
|
answerid := ctx.Param("answerid")
|
|
|
|
detail, err := tc.templateRenderController.QuestionDetail(ctx, id)
|
|
if err != nil {
|
|
tc.Page404(ctx)
|
|
return
|
|
}
|
|
|
|
// answers
|
|
answerReq := &schema.AnswerList{
|
|
QuestionID: id,
|
|
Order: "",
|
|
Page: 1,
|
|
PageSize: 999,
|
|
LoginUserID: "",
|
|
}
|
|
answers, answerCount, err := tc.templateRenderController.AnswerList(ctx, answerReq)
|
|
if err != nil {
|
|
tc.Page404(ctx)
|
|
return
|
|
}
|
|
|
|
// comments
|
|
objectIDs := []string{id}
|
|
for _, answer := range answers {
|
|
objectIDs = append(objectIDs, answer.ID)
|
|
}
|
|
comments, err := tc.templateRenderController.CommentList(ctx, objectIDs)
|
|
if err != nil {
|
|
tc.Page404(ctx)
|
|
return
|
|
}
|
|
siteInfo := tc.SiteInfo(ctx)
|
|
encodeTitle := htmltext.UrlTitle(detail.Title)
|
|
siteInfo.Canonical = fmt.Sprintf("%s/questions/%s/%s", siteInfo.General.SiteUrl, id, encodeTitle)
|
|
if siteInfo.General.PermaLink == schema.PermaLinkQuestionID {
|
|
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 = htmltext.ClearText(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
|
|
answerList := make([]*schema.SuggestedAnswerItem, 0)
|
|
for _, answer := range answers {
|
|
item := &schema.SuggestedAnswerItem{}
|
|
item.Type = "Answer"
|
|
item.Text = htmltext.ClearText(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
|
|
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>`
|
|
}
|
|
|
|
tc.html(ctx, http.StatusOK, "question-detail.html", siteInfo, gin.H{
|
|
"id": id,
|
|
"answerid": answerid,
|
|
"detail": detail,
|
|
"answers": answers,
|
|
"comments": comments,
|
|
})
|
|
}
|
|
|
|
// TagList tags list
|
|
func (tc *TemplateController) TagList(ctx *gin.Context) {
|
|
req := &schema.GetTagWithPageReq{}
|
|
if handler.BindAndCheck(ctx, req) {
|
|
return
|
|
}
|
|
data, err := tc.templateRenderController.TagList(ctx, req)
|
|
if err != nil {
|
|
ctx.HTML(http.StatusOK, "404.html", gin.H{
|
|
"scriptPath": tc.scriptPath,
|
|
"cssPath": tc.cssPath,
|
|
"err": err.Error(),
|
|
"siteinfo": tc.SiteInfo(ctx),
|
|
})
|
|
return
|
|
}
|
|
page := templaterender.Paginator(req.Page, req.PageSize, data.Count)
|
|
|
|
siteInfo := tc.SiteInfo(ctx)
|
|
siteInfo.Canonical = fmt.Sprintf("%s/tags", siteInfo.General.SiteUrl)
|
|
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) {
|
|
ctx.HTML(http.StatusOK, "404.html", gin.H{
|
|
"scriptPath": tc.scriptPath,
|
|
"cssPath": tc.cssPath,
|
|
"err": "",
|
|
"siteinfo": tc.SiteInfo(ctx),
|
|
})
|
|
return
|
|
}
|
|
nowPage := req.Page
|
|
req.Name = tag
|
|
taginifo, questionList, questionCount, err := tc.templateRenderController.TagInfo(ctx, req)
|
|
if err != nil {
|
|
ctx.HTML(http.StatusOK, "404.html", gin.H{
|
|
"scriptPath": tc.scriptPath,
|
|
"cssPath": tc.cssPath,
|
|
"err": err.Error(),
|
|
"siteinfo": tc.SiteInfo(ctx),
|
|
})
|
|
return
|
|
}
|
|
page := templaterender.Paginator(nowPage, req.PageSize, questionCount)
|
|
|
|
siteInfo := tc.SiteInfo(ctx)
|
|
siteInfo.Canonical = fmt.Sprintf("%s/tags/%s", siteInfo.General.SiteUrl, tag)
|
|
tc.html(ctx, http.StatusOK, "tag-detail.html", siteInfo, gin.H{
|
|
"tag": taginifo,
|
|
"questionList": questionList,
|
|
"questionCount": questionCount,
|
|
"page": page,
|
|
})
|
|
}
|
|
|
|
// UserInfo user info
|
|
func (tc *TemplateController) UserInfo(ctx *gin.Context) {
|
|
username := ctx.Param("username")
|
|
req := &schema.GetOtherUserInfoByUsernameReq{}
|
|
req.Username = username
|
|
userinfo, err := tc.templateRenderController.UserInfo(ctx, req)
|
|
if !userinfo.Has {
|
|
ctx.HTML(http.StatusNotFound, "404.html", gin.H{
|
|
"siteinfo": tc.SiteInfo(ctx),
|
|
"scriptPath": tc.scriptPath,
|
|
"cssPath": tc.cssPath,
|
|
"err": "",
|
|
})
|
|
return
|
|
}
|
|
if err != nil {
|
|
ctx.HTML(http.StatusNotFound, "404.html", gin.H{
|
|
"siteinfo": tc.SiteInfo(ctx),
|
|
"scriptPath": tc.scriptPath,
|
|
"cssPath": tc.cssPath,
|
|
"err": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
siteInfo := tc.SiteInfo(ctx)
|
|
siteInfo.Canonical = fmt.Sprintf("%s/users/%s", siteInfo.General.SiteUrl, username)
|
|
tc.html(ctx, http.StatusOK, "homepage.html", siteInfo, gin.H{
|
|
"userinfo": userinfo,
|
|
"bio": template.HTML(userinfo.Info.BioHTML),
|
|
})
|
|
}
|
|
|
|
func (tc *TemplateController) Page404(ctx *gin.Context) {
|
|
ctx.HTML(http.StatusNotFound, "404.html", gin.H{
|
|
"siteinfo": tc.SiteInfo(ctx),
|
|
"scriptPath": tc.scriptPath,
|
|
"cssPath": tc.cssPath,
|
|
})
|
|
}
|
|
|
|
func (tc *TemplateController) html(ctx *gin.Context, code int, tpl string, siteInfo *schema.TemplateSiteInfoResp, data gin.H) {
|
|
data["siteinfo"] = siteInfo
|
|
data["scriptPath"] = tc.scriptPath
|
|
data["cssPath"] = tc.cssPath
|
|
data["language"] = handler.GetLang(ctx)
|
|
data["timezone"] = siteInfo.Interface.TimeZone
|
|
|
|
ctx.HTML(code, tpl, data)
|
|
}
|