Merge branch 'main' of github.com:answerdev/answer

This commit is contained in:
aichy126 2023-06-12 18:00:22 +08:00
commit e1df1cbfc2
9 changed files with 145 additions and 74 deletions

View File

@ -165,7 +165,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
answerCommon := answercommon.NewAnswerCommon(answerRepo) answerCommon := answercommon.NewAnswerCommon(answerRepo)
metaRepo := meta.NewMetaRepo(dataData) metaRepo := meta.NewMetaRepo(dataData)
metaService := meta2.NewMetaService(metaRepo) metaService := meta2.NewMetaService(metaRepo)
questionCommon := questioncommon.NewQuestionCommon(questionRepo, answerRepo, voteRepo, followRepo, tagCommonService, userCommon, collectionCommon, answerCommon, metaService, configService) questionCommon := questioncommon.NewQuestionCommon(questionRepo, answerRepo, voteRepo, followRepo, tagCommonService, userCommon, collectionCommon, answerCommon, metaService, configService, dataData)
collectionService := service.NewCollectionService(collectionRepo, collectionGroupRepo, questionCommon) collectionService := service.NewCollectionService(collectionRepo, collectionGroupRepo, questionCommon)
collectionController := controller.NewCollectionController(collectionService) collectionController := controller.NewCollectionController(collectionService)
answerActivityRepo := activity.NewAnswerActivityRepo(dataData, activityRepo, userRankRepo) answerActivityRepo := activity.NewAnswerActivityRepo(dataData, activityRepo, userRankRepo)
@ -193,7 +193,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
reasonService := reason2.NewReasonService(reasonRepo) reasonService := reason2.NewReasonService(reasonRepo)
reasonController := controller.NewReasonController(reasonService) reasonController := controller.NewReasonController(reasonService)
themeController := controller_admin.NewThemeController() themeController := controller_admin.NewThemeController()
siteInfoService := siteinfo.NewSiteInfoService(siteInfoRepo, siteInfoCommonService, emailService, tagCommonService, configService) siteInfoService := siteinfo.NewSiteInfoService(siteInfoRepo, siteInfoCommonService, emailService, tagCommonService, configService, questionCommon)
siteInfoController := controller_admin.NewSiteInfoController(siteInfoService) siteInfoController := controller_admin.NewSiteInfoController(siteInfoService)
siteinfoController := controller.NewSiteinfoController(siteInfoCommonService) siteinfoController := controller.NewSiteinfoController(siteInfoCommonService)
notificationRepo := notification.NewNotificationRepo(dataData) notificationRepo := notification.NewNotificationRepo(dataData)

View File

@ -4,6 +4,8 @@ import (
"bytes" "bytes"
"embed" "embed"
"fmt" "fmt"
"io"
"io/fs"
"os" "os"
"os/exec" "os/exec"
"path" "path"
@ -286,34 +288,56 @@ func mergeI18nFiles(b *buildingMaterial) (err error) {
} }
func copyDirEntries(sourceFs embed.FS, sourceDir string, targetDir string) (err error) { func copyDirEntries(sourceFs embed.FS, sourceDir string, targetDir string) (err error) {
entries, err := ui.Build.ReadDir(sourceDir)
if err != nil {
return err
}
err = dir.CreateDirIfNotExist(targetDir) err = dir.CreateDirIfNotExist(targetDir)
if err != nil { if err != nil {
return err return err
} }
for _, entry := range entries { err = fs.WalkDir(sourceFs, sourceDir, func(path string, d fs.DirEntry, err error) error {
if entry.IsDir() {
err = copyDirEntries(sourceFs, filepath.Join(sourceDir, entry.Name()), filepath.Join(targetDir, entry.Name()))
if err != nil { if err != nil {
return err return err
} }
continue
} // Convert the path to use forward slashes, important because we use embedded FS which always uses forward slashes
file, err := sourceFs.ReadFile(filepath.Join(sourceDir, entry.Name())) path = filepath.ToSlash(path)
// Construct the absolute path for the source file/directory
srcPath := filepath.Join(sourceDir, path)
// Construct the absolute path for the destination file/directory
dstPath := filepath.Join(targetDir, path)
if d.IsDir() {
// Create the directory in the destination
err := os.MkdirAll(dstPath, d.Type())
if err != nil { if err != nil {
return err return err
} }
filename := filepath.Join(targetDir, entry.Name()) } else {
err = os.WriteFile(filename, file, 0666) // Open the source file
srcFile, err := sourceFs.Open(srcPath)
if err != nil {
return err
}
defer srcFile.Close()
// Create the destination file
dstFile, err := os.Create(dstPath)
if err != nil {
return err
}
defer dstFile.Close()
// Copy the file contents
_, err = io.Copy(dstFile, srcFile)
if err != nil { if err != nil {
return err return err
} }
} }
return nil return nil
})
return err
} }
func buildBinary(b *buildingMaterial) (err error) { func buildBinary(b *buildingMaterial) (err error) {

View File

@ -25,6 +25,11 @@ func (t *TemplateRenderController) Sitemap(ctx *gin.Context) {
log.Error("get site general failed:", err) log.Error("get site general failed:", err)
return return
} }
siteInfo, err := t.siteInfoService.GetSiteSeo(ctx)
if err != nil {
log.Error("get site GetSiteSeo failed:", err)
return
}
sitemapInfo := &schema.SiteMapList{} sitemapInfo := &schema.SiteMapList{}
infoStr, err := t.data.Cache.GetString(ctx, schema.SitemapCachekey) infoStr, err := t.data.Cache.GetString(ctx, schema.SitemapCachekey)
@ -32,6 +37,10 @@ func (t *TemplateRenderController) Sitemap(ctx *gin.Context) {
log.Errorf("get Cache failed: %s", err) log.Errorf("get Cache failed: %s", err)
return return
} }
hasTitle := false
if siteInfo.PermaLink == schema.PermaLinkQuestionIDAndTitle || siteInfo.PermaLink == schema.PermaLinkQuestionIDAndTitleByShortID {
hasTitle = true
}
if err = json.Unmarshal([]byte(infoStr), sitemapInfo); err != nil { if err = json.Unmarshal([]byte(infoStr), sitemapInfo); err != nil {
log.Errorf("get sitemap info failed: %s", err) log.Errorf("get sitemap info failed: %s", err)
return return
@ -45,6 +54,7 @@ func (t *TemplateRenderController) Sitemap(ctx *gin.Context) {
"xmlHeader": template.HTML(`<?xml version="1.0" encoding="UTF-8"?>`), "xmlHeader": template.HTML(`<?xml version="1.0" encoding="UTF-8"?>`),
"list": sitemapInfo.QuestionIDs, "list": sitemapInfo.QuestionIDs,
"general": general, "general": general,
"hastitle": hasTitle,
}, },
) )
} else { } else {
@ -68,6 +78,15 @@ func (t *TemplateRenderController) SitemapPage(ctx *gin.Context, page int) error
log.Error("get site general failed:", err) log.Error("get site general failed:", err)
return err return err
} }
siteInfo, err := t.siteInfoService.GetSiteSeo(ctx)
if err != nil {
log.Error("get site GetSiteSeo failed:", err)
return err
}
hasTitle := false
if siteInfo.PermaLink == schema.PermaLinkQuestionIDAndTitle || siteInfo.PermaLink == schema.PermaLinkQuestionIDAndTitleByShortID {
hasTitle = true
}
cachekey := fmt.Sprintf(schema.SitemapPageCachekey, page) cachekey := fmt.Sprintf(schema.SitemapPageCachekey, page)
infoStr, err := t.data.Cache.GetString(ctx, cachekey) infoStr, err := t.data.Cache.GetString(ctx, cachekey)
@ -85,6 +104,7 @@ func (t *TemplateRenderController) SitemapPage(ctx *gin.Context, page int) error
"xmlHeader": template.HTML(`<?xml version="1.0" encoding="UTF-8"?>`), "xmlHeader": template.HTML(`<?xml version="1.0" encoding="UTF-8"?>`),
"list": sitemapInfo.PageData, "list": sitemapInfo.PageData,
"general": general, "general": general,
"hastitle": hasTitle,
}, },
) )
return nil return nil

View File

@ -224,7 +224,7 @@ func updateTagCount(x *xorm.Engine) error {
} }
} else { } else {
tag.QuestionCount = 0 tag.QuestionCount = 0
if _, err = x.Update(tag, &entity.Tag{ID: tag.ID}); err != nil { if _, err = x.Cols("question_count").Update(tag, &entity.Tag{ID: tag.ID}); err != nil {
log.Errorf("update %+v tag failed: %s", tag.ID, err) log.Errorf("update %+v tag failed: %s", tag.ID, err)
return fmt.Errorf("update tag failed: %w", err) return fmt.Errorf("update tag failed: %w", err)
} }

View File

@ -10,6 +10,7 @@ import (
"github.com/answerdev/answer/internal/entity" "github.com/answerdev/answer/internal/entity"
collectioncommon "github.com/answerdev/answer/internal/service/collection_common" collectioncommon "github.com/answerdev/answer/internal/service/collection_common"
"github.com/answerdev/answer/internal/service/unique" "github.com/answerdev/answer/internal/service/unique"
"github.com/answerdev/answer/pkg/uid"
"github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/errors"
"xorm.io/xorm" "xorm.io/xorm"
) )
@ -148,6 +149,9 @@ func (cr *collectionRepo) GetCollectionPage(ctx context.Context, page, pageSize
// SearchObjectCollected check object is collected or not // SearchObjectCollected check object is collected or not
func (cr *collectionRepo) SearchObjectCollected(ctx context.Context, userID string, objectIds []string) (map[string]bool, error) { func (cr *collectionRepo) SearchObjectCollected(ctx context.Context, userID string, objectIds []string) (map[string]bool, error) {
collectedMap := make(map[string]bool) collectedMap := make(map[string]bool)
for k, object_id := range objectIds {
objectIds[k] = uid.DeShortID(object_id)
}
list, err := cr.SearchByObjectIDsAndUser(ctx, userID, objectIds) list, err := cr.SearchByObjectIDsAndUser(ctx, userID, objectIds)
if err != nil { if err != nil {
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()

View File

@ -3,9 +3,12 @@ package questioncommon
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"fmt"
"math"
"time" "time"
"github.com/answerdev/answer/internal/base/constant" "github.com/answerdev/answer/internal/base/constant"
"github.com/answerdev/answer/internal/base/data"
"github.com/answerdev/answer/internal/base/handler" "github.com/answerdev/answer/internal/base/handler"
"github.com/answerdev/answer/internal/base/reason" "github.com/answerdev/answer/internal/base/reason"
"github.com/answerdev/answer/internal/service/activity_common" "github.com/answerdev/answer/internal/service/activity_common"
@ -64,6 +67,7 @@ type QuestionCommon struct {
AnswerCommon *answercommon.AnswerCommon AnswerCommon *answercommon.AnswerCommon
metaService *meta.MetaService metaService *meta.MetaService
configService *config.ConfigService configService *config.ConfigService
data *data.Data
} }
func NewQuestionCommon(questionRepo QuestionRepo, func NewQuestionCommon(questionRepo QuestionRepo,
@ -76,6 +80,8 @@ func NewQuestionCommon(questionRepo QuestionRepo,
answerCommon *answercommon.AnswerCommon, answerCommon *answercommon.AnswerCommon,
metaService *meta.MetaService, metaService *meta.MetaService,
configService *config.ConfigService, configService *config.ConfigService,
data *data.Data,
) *QuestionCommon { ) *QuestionCommon {
return &QuestionCommon{ return &QuestionCommon{
questionRepo: questionRepo, questionRepo: questionRepo,
@ -88,6 +94,7 @@ func NewQuestionCommon(questionRepo QuestionRepo,
AnswerCommon: answerCommon, AnswerCommon: answerCommon,
metaService: metaService, metaService: metaService,
configService: configService, configService: configService,
data: data,
} }
} }
@ -543,6 +550,57 @@ func (as *QuestionCommon) RemoveAnswer(ctx context.Context, id string) (err erro
return as.answerRepo.RemoveAnswer(ctx, id) return as.answerRepo.RemoveAnswer(ctx, id)
} }
func (qs *QuestionCommon) SitemapCron(ctx context.Context) {
data := &schema.SiteMapList{}
questionNum, err := qs.questionRepo.GetQuestionCount(ctx)
if err != nil {
log.Error("GetQuestionCount error", err)
return
}
if questionNum <= schema.SitemapMaxSize {
questionIDList, err := qs.questionRepo.GetQuestionIDsPage(ctx, 0, int(questionNum))
if err != nil {
log.Error("GetQuestionIDsPage error", err)
return
}
data.QuestionIDs = questionIDList
} else {
nums := make([]int, 0)
totalpages := int(math.Ceil(float64(questionNum) / float64(schema.SitemapMaxSize)))
for i := 1; i <= totalpages; i++ {
siteMapPagedata := &schema.SiteMapPageList{}
nums = append(nums, i)
questionIDList, err := qs.questionRepo.GetQuestionIDsPage(ctx, i, int(schema.SitemapMaxSize))
if err != nil {
log.Error("GetQuestionIDsPage error", err)
return
}
siteMapPagedata.PageData = questionIDList
if setCacheErr := qs.SetCache(ctx, fmt.Sprintf(schema.SitemapPageCachekey, i), siteMapPagedata); setCacheErr != nil {
log.Errorf("set sitemap cron SetCache failed: %s", setCacheErr)
}
}
data.MaxPageNum = nums
}
if setCacheErr := qs.SetCache(ctx, schema.SitemapCachekey, data); setCacheErr != nil {
log.Errorf("set sitemap cron SetCache failed: %s", setCacheErr)
}
}
func (qs *QuestionCommon) SetCache(ctx context.Context, cachekey string, info interface{}) error {
infoStr, err := json.Marshal(info)
if err != nil {
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
}
err = qs.data.Cache.SetString(ctx, cachekey, string(infoStr), schema.DashBoardCacheTime)
if err != nil {
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
}
return nil
}
func (qs *QuestionCommon) ShowListFormat(ctx context.Context, data *entity.Question) *schema.QuestionInfo { func (qs *QuestionCommon) ShowListFormat(ctx context.Context, data *entity.Question) *schema.QuestionInfo {
return qs.ShowFormat(ctx, data) return qs.ShowFormat(ctx, data)
} }

View File

@ -3,7 +3,6 @@ package service
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"math"
"strings" "strings"
"time" "time"
@ -589,13 +588,16 @@ func (qs *QuestionService) UpdateQuestionInviteUser(ctx context.Context, req *sc
//send notification //send notification
oldInviteUserIDsStr := originQuestion.InviteUserID oldInviteUserIDsStr := originQuestion.InviteUserID
oldInviteUserIDs := make([]string, 0) oldInviteUserIDs := make([]string, 0)
needSendNotificationUserIDs := make([]string, 0)
if oldInviteUserIDsStr != "" { if oldInviteUserIDsStr != "" {
err = json.Unmarshal([]byte(oldInviteUserIDsStr), &oldInviteUserIDs) err = json.Unmarshal([]byte(oldInviteUserIDsStr), &oldInviteUserIDs)
if err == nil { if err == nil {
needSendNotificationUserIDs := converter.ArrayNotInArray(oldInviteUserIDs, inviteUserIDs) needSendNotificationUserIDs = converter.ArrayNotInArray(oldInviteUserIDs, inviteUserIDs)
}
} else {
needSendNotificationUserIDs = inviteUserIDs
}
go qs.notificationInviteUser(ctx, needSendNotificationUserIDs, originQuestion.ID, originQuestion.Title, req.UserID) go qs.notificationInviteUser(ctx, needSendNotificationUserIDs, originQuestion.ID, originQuestion.Title, req.UserID)
}
}
return nil return nil
} }
@ -1344,52 +1346,5 @@ func (qs *QuestionService) changeQuestionToRevision(ctx context.Context, questio
} }
func (qs *QuestionService) SitemapCron(ctx context.Context) { func (qs *QuestionService) SitemapCron(ctx context.Context) {
data := &schema.SiteMapList{} qs.questioncommon.SitemapCron(ctx)
questionNum, err := qs.questionRepo.GetQuestionCount(ctx)
if err != nil {
log.Error("GetQuestionCount error", err)
return
}
if questionNum <= schema.SitemapMaxSize {
questionIDList, err := qs.questionRepo.GetQuestionIDsPage(ctx, 0, int(questionNum))
if err != nil {
log.Error("GetQuestionIDsPage error", err)
return
}
data.QuestionIDs = questionIDList
} else {
nums := make([]int, 0)
totalpages := int(math.Ceil(float64(questionNum) / float64(schema.SitemapMaxSize)))
for i := 1; i <= totalpages; i++ {
siteMapPagedata := &schema.SiteMapPageList{}
nums = append(nums, i)
questionIDList, err := qs.questionRepo.GetQuestionIDsPage(ctx, i, int(schema.SitemapMaxSize))
if err != nil {
log.Error("GetQuestionIDsPage error", err)
return
}
siteMapPagedata.PageData = questionIDList
if setCacheErr := qs.SetCache(ctx, fmt.Sprintf(schema.SitemapPageCachekey, i), siteMapPagedata); setCacheErr != nil {
log.Errorf("set sitemap cron SetCache failed: %s", setCacheErr)
}
}
data.MaxPageNum = nums
}
if setCacheErr := qs.SetCache(ctx, schema.SitemapCachekey, data); setCacheErr != nil {
log.Errorf("set sitemap cron SetCache failed: %s", setCacheErr)
}
}
func (qs *QuestionService) SetCache(ctx context.Context, cachekey string, info interface{}) error {
infoStr, err := json.Marshal(info)
if err != nil {
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
}
err = qs.data.Cache.SetString(ctx, cachekey, string(infoStr), schema.DashBoardCacheTime)
if err != nil {
return errors.InternalServer(reason.UnknownError).WithError(err).WithStack()
}
return nil
} }

View File

@ -13,6 +13,7 @@ import (
"github.com/answerdev/answer/internal/schema" "github.com/answerdev/answer/internal/schema"
"github.com/answerdev/answer/internal/service/config" "github.com/answerdev/answer/internal/service/config"
"github.com/answerdev/answer/internal/service/export" "github.com/answerdev/answer/internal/service/export"
questioncommon "github.com/answerdev/answer/internal/service/question_common"
"github.com/answerdev/answer/internal/service/siteinfo_common" "github.com/answerdev/answer/internal/service/siteinfo_common"
tagcommon "github.com/answerdev/answer/internal/service/tag_common" tagcommon "github.com/answerdev/answer/internal/service/tag_common"
"github.com/answerdev/answer/pkg/uid" "github.com/answerdev/answer/pkg/uid"
@ -28,6 +29,7 @@ type SiteInfoService struct {
emailService *export.EmailService emailService *export.EmailService
tagCommonService *tagcommon.TagCommonService tagCommonService *tagcommon.TagCommonService
configService *config.ConfigService configService *config.ConfigService
questioncommon *questioncommon.QuestionCommon
} }
func NewSiteInfoService( func NewSiteInfoService(
@ -36,6 +38,8 @@ func NewSiteInfoService(
emailService *export.EmailService, emailService *export.EmailService,
tagCommonService *tagcommon.TagCommonService, tagCommonService *tagcommon.TagCommonService,
configService *config.ConfigService, configService *config.ConfigService,
questioncommon *questioncommon.QuestionCommon,
) *SiteInfoService { ) *SiteInfoService {
plugin.RegisterGetSiteURLFunc(func() string { plugin.RegisterGetSiteURLFunc(func() string {
generalSiteInfo, err := siteInfoCommonService.GetSiteGeneral(context.Background()) generalSiteInfo, err := siteInfoCommonService.GetSiteGeneral(context.Background())
@ -52,6 +56,7 @@ func NewSiteInfoService(
emailService: emailService, emailService: emailService,
tagCommonService: tagCommonService, tagCommonService: tagCommonService,
configService: configService, configService: configService,
questioncommon: questioncommon,
} }
} }
@ -295,6 +300,7 @@ func (s *SiteInfoService) SaveSeo(ctx context.Context, req schema.SiteSeoReq) (e
} else { } else {
uid.ShortIDSwitch = false uid.ShortIDSwitch = false
} }
s.questioncommon.SitemapCron(ctx)
return return
} }

View File

@ -2,7 +2,11 @@
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
{{ range .list }} {{ range .list }}
<url> <url>
{{if $.hastitle}}
<loc>{{$.general.SiteUrl}}/questions/{{.ID}}/{{.Title}}</loc> <loc>{{$.general.SiteUrl}}/questions/{{.ID}}/{{.Title}}</loc>
{{else}}
<loc>{{$.general.SiteUrl}}/questions/{{.ID}}</loc>
{{end}}
<lastmod>{{.UpdateTime}}</lastmod> <lastmod>{{.UpdateTime}}</lastmod>
</url> </url>
{{ end }} {{ end }}