327 lines
12 KiB
Go
327 lines
12 KiB
Go
/*
|
|
* 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 siteinfo_common
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"html"
|
|
|
|
"github.com/apache/answer/internal/base/constant"
|
|
"github.com/apache/answer/internal/entity"
|
|
"github.com/apache/answer/internal/schema"
|
|
"github.com/apache/answer/pkg/checker"
|
|
"github.com/apache/answer/pkg/gravatar"
|
|
"github.com/segmentfault/pacman/log"
|
|
)
|
|
|
|
//go:generate mockgen -source=./siteinfo_service.go -destination=../mock/siteinfo_repo_mock.go -package=mock
|
|
type SiteInfoRepo interface {
|
|
SaveByType(ctx context.Context, siteType string, data *entity.SiteInfo) (err error)
|
|
GetByType(ctx context.Context, siteType string, withoutCache ...bool) (siteInfo *entity.SiteInfo, exist bool, err error)
|
|
IsBrandingFileUsed(ctx context.Context, filePath string) (bool, error)
|
|
}
|
|
|
|
// siteInfoCommonService site info common service
|
|
type siteInfoCommonService struct {
|
|
siteInfoRepo SiteInfoRepo
|
|
}
|
|
|
|
type SiteInfoCommonService interface {
|
|
GetSiteGeneral(ctx context.Context) (resp *schema.SiteGeneralResp, err error)
|
|
GetSiteInterface(ctx context.Context) (resp *schema.SiteInterfaceSettingsResp, err error)
|
|
GetSiteUsersSettings(ctx context.Context) (resp *schema.SiteUsersSettingsResp, err error)
|
|
GetSiteBranding(ctx context.Context) (resp *schema.SiteBrandingResp, err error)
|
|
GetSiteUsers(ctx context.Context) (resp *schema.SiteUsersResp, err error)
|
|
FormatAvatar(ctx context.Context, originalAvatarData, email string, userStatus int) *schema.AvatarInfo
|
|
FormatListAvatar(ctx context.Context, userList []*entity.User) (userID2AvatarMapping map[string]*schema.AvatarInfo)
|
|
GetSiteWrite(ctx context.Context) (resp *schema.SiteWriteResp, err error)
|
|
GetSiteAdvanced(ctx context.Context) (resp *schema.SiteAdvancedResp, err error)
|
|
GetSiteQuestion(ctx context.Context) (resp *schema.SiteQuestionsResp, err error)
|
|
GetSiteTag(ctx context.Context) (resp *schema.SiteTagsResp, err error)
|
|
GetSitePolicies(ctx context.Context) (resp *schema.SitePoliciesResp, err error)
|
|
GetSiteSecurity(ctx context.Context) (resp *schema.SiteSecurityResp, err error)
|
|
GetSiteLogin(ctx context.Context) (resp *schema.SiteLoginResp, err error)
|
|
GetSiteCustomCssHTML(ctx context.Context) (resp *schema.SiteCustomCssHTMLResp, err error)
|
|
GetSiteTheme(ctx context.Context) (resp *schema.SiteThemeResp, err error)
|
|
GetSiteSeo(ctx context.Context) (resp *schema.SiteSeoResp, err error)
|
|
GetSiteInfoByType(ctx context.Context, siteType string, resp any) (err error)
|
|
IsBrandingFileUsed(ctx context.Context, filePath string) bool
|
|
GetSiteAI(ctx context.Context) (resp *schema.SiteAIResp, err error)
|
|
GetSiteMCP(ctx context.Context) (resp *schema.SiteMCPResp, err error)
|
|
}
|
|
|
|
// NewSiteInfoCommonService new site info common service
|
|
func NewSiteInfoCommonService(siteInfoRepo SiteInfoRepo) SiteInfoCommonService {
|
|
return &siteInfoCommonService{
|
|
siteInfoRepo: siteInfoRepo,
|
|
}
|
|
}
|
|
|
|
// GetSiteGeneral get site info general
|
|
func (s *siteInfoCommonService) GetSiteGeneral(ctx context.Context) (resp *schema.SiteGeneralResp, err error) {
|
|
resp = &schema.SiteGeneralResp{}
|
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeGeneral, resp); err != nil {
|
|
return nil, err
|
|
}
|
|
resp.Name = html.UnescapeString(resp.Name)
|
|
return resp, nil
|
|
}
|
|
|
|
// GetSiteInterface get site info interface
|
|
func (s *siteInfoCommonService) GetSiteInterface(ctx context.Context) (resp *schema.SiteInterfaceSettingsResp, err error) {
|
|
resp = &schema.SiteInterfaceSettingsResp{}
|
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeInterfaceSettings, resp); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetSiteUsersSettings get site info interface
|
|
func (s *siteInfoCommonService) GetSiteUsersSettings(ctx context.Context) (resp *schema.SiteUsersSettingsResp, err error) {
|
|
resp = &schema.SiteUsersSettingsResp{}
|
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeUsersSettings, resp); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetSiteBranding get site info branding
|
|
func (s *siteInfoCommonService) GetSiteBranding(ctx context.Context) (resp *schema.SiteBrandingResp, err error) {
|
|
resp = &schema.SiteBrandingResp{}
|
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeBranding, resp); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetSiteUsers get site info about users
|
|
func (s *siteInfoCommonService) GetSiteUsers(ctx context.Context) (resp *schema.SiteUsersResp, err error) {
|
|
resp = &schema.SiteUsersResp{}
|
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeUsers, resp); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// FormatAvatar format avatar
|
|
func (s *siteInfoCommonService) FormatAvatar(ctx context.Context, originalAvatarData, email string, userStatus int) *schema.AvatarInfo {
|
|
gravatarBaseURL, defaultAvatar := s.getAvatarDefaultConfig(ctx)
|
|
return s.selectedAvatar(originalAvatarData, defaultAvatar, gravatarBaseURL, email, userStatus)
|
|
}
|
|
|
|
// FormatListAvatar format avatar
|
|
func (s *siteInfoCommonService) FormatListAvatar(ctx context.Context, userList []*entity.User) (
|
|
avatarMapping map[string]*schema.AvatarInfo) {
|
|
gravatarBaseURL, defaultAvatar := s.getAvatarDefaultConfig(ctx)
|
|
avatarMapping = make(map[string]*schema.AvatarInfo)
|
|
for _, user := range userList {
|
|
avatarMapping[user.ID] = s.selectedAvatar(user.Avatar, defaultAvatar, gravatarBaseURL, user.EMail, user.Status)
|
|
}
|
|
return avatarMapping
|
|
}
|
|
|
|
func (s *siteInfoCommonService) getAvatarDefaultConfig(ctx context.Context) (string, string) {
|
|
gravatarBaseURL, defaultAvatar := constant.DefaultGravatarBaseURL, constant.DefaultAvatar
|
|
usersConfig, err := s.GetSiteUsersSettings(ctx)
|
|
if err != nil {
|
|
log.Error(err)
|
|
}
|
|
if len(usersConfig.GravatarBaseURL) > 0 {
|
|
gravatarBaseURL = usersConfig.GravatarBaseURL
|
|
}
|
|
if len(usersConfig.DefaultAvatar) > 0 {
|
|
defaultAvatar = usersConfig.DefaultAvatar
|
|
}
|
|
return gravatarBaseURL, defaultAvatar
|
|
}
|
|
|
|
func (s *siteInfoCommonService) selectedAvatar(
|
|
originalAvatarData,
|
|
defaultAvatar, gravatarBaseURL,
|
|
email string, userStatus int) *schema.AvatarInfo {
|
|
avatarInfo := &schema.AvatarInfo{}
|
|
_ = json.Unmarshal([]byte(originalAvatarData), avatarInfo)
|
|
if len(avatarInfo.Type) == 0 && checker.IsURL(originalAvatarData) {
|
|
avatarInfo.Type = constant.AvatarTypeCustom
|
|
avatarInfo.Custom = originalAvatarData
|
|
}
|
|
|
|
if userStatus == entity.UserStatusDeleted {
|
|
return &schema.AvatarInfo{
|
|
Type: constant.DefaultAvatar,
|
|
}
|
|
}
|
|
|
|
if len(avatarInfo.Type) == 0 && defaultAvatar == constant.AvatarTypeGravatar {
|
|
avatarInfo.Type = constant.AvatarTypeGravatar
|
|
avatarInfo.Gravatar = gravatar.GetAvatarURL(gravatarBaseURL, email)
|
|
} else if avatarInfo.Type == constant.AvatarTypeGravatar {
|
|
avatarInfo.Gravatar = gravatar.GetAvatarURL(gravatarBaseURL, email)
|
|
}
|
|
return avatarInfo
|
|
}
|
|
|
|
// GetSiteWrite get site info write
|
|
func (s *siteInfoCommonService) GetSiteWrite(ctx context.Context) (resp *schema.SiteWriteResp, err error) {
|
|
resp = &schema.SiteWriteResp{}
|
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeWrite, resp); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetSiteAdvanced get site info advanced
|
|
func (s *siteInfoCommonService) GetSiteAdvanced(ctx context.Context) (resp *schema.SiteAdvancedResp, err error) {
|
|
resp = &schema.SiteAdvancedResp{}
|
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeAdvanced, resp); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetSiteQuestion get site info question
|
|
func (s *siteInfoCommonService) GetSiteQuestion(ctx context.Context) (resp *schema.SiteQuestionsResp, err error) {
|
|
resp = &schema.SiteQuestionsResp{}
|
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeQuestions, resp); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetSiteTag get site info tag
|
|
func (s *siteInfoCommonService) GetSiteTag(ctx context.Context) (resp *schema.SiteTagsResp, err error) {
|
|
resp = &schema.SiteTagsResp{}
|
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeTags, resp); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetSitePolicies get site info policies
|
|
func (s *siteInfoCommonService) GetSitePolicies(ctx context.Context) (resp *schema.SitePoliciesResp, err error) {
|
|
resp = &schema.SitePoliciesResp{}
|
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypePolicies, resp); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetSiteSecurity get site security config
|
|
func (s *siteInfoCommonService) GetSiteSecurity(ctx context.Context) (resp *schema.SiteSecurityResp, err error) {
|
|
resp = &schema.SiteSecurityResp{CheckUpdate: true}
|
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeSecurity, resp); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetSiteLogin get site login config
|
|
func (s *siteInfoCommonService) GetSiteLogin(ctx context.Context) (resp *schema.SiteLoginResp, err error) {
|
|
resp = &schema.SiteLoginResp{RequireEmailVerification: true}
|
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeLogin, resp); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetSiteCustomCssHTML get site custom css html config
|
|
func (s *siteInfoCommonService) GetSiteCustomCssHTML(ctx context.Context) (resp *schema.SiteCustomCssHTMLResp, err error) {
|
|
resp = &schema.SiteCustomCssHTMLResp{}
|
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeCustomCssHTML, resp); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetSiteTheme get site theme
|
|
func (s *siteInfoCommonService) GetSiteTheme(ctx context.Context) (resp *schema.SiteThemeResp, err error) {
|
|
resp = &schema.SiteThemeResp{
|
|
ThemeOptions: schema.GetThemeOptions,
|
|
Layout: constant.ThemeLayoutFullWidth,
|
|
}
|
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeTheme, resp); err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.Layout == "" {
|
|
resp.Layout = constant.ThemeLayoutFullWidth
|
|
}
|
|
resp.TrTheme(ctx)
|
|
return resp, nil
|
|
}
|
|
|
|
// GetSiteSeo get site seo
|
|
func (s *siteInfoCommonService) GetSiteSeo(ctx context.Context) (resp *schema.SiteSeoResp, err error) {
|
|
resp = &schema.SiteSeoResp{}
|
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeSeo, resp); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (s *siteInfoCommonService) EnableShortID(ctx context.Context) (enabled bool) {
|
|
siteSeo, err := s.GetSiteSeo(ctx)
|
|
if err != nil {
|
|
log.Error(err)
|
|
return false
|
|
}
|
|
return siteSeo.IsShortLink()
|
|
}
|
|
|
|
func (s *siteInfoCommonService) GetSiteInfoByType(ctx context.Context, siteType string, resp any) (err error) {
|
|
siteInfo, exist, err := s.siteInfoRepo.GetByType(ctx, siteType)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !exist {
|
|
return nil
|
|
}
|
|
_ = json.Unmarshal([]byte(siteInfo.Content), resp)
|
|
return nil
|
|
}
|
|
|
|
func (s *siteInfoCommonService) IsBrandingFileUsed(ctx context.Context, filePath string) bool {
|
|
used, err := s.siteInfoRepo.IsBrandingFileUsed(ctx, filePath)
|
|
if err != nil {
|
|
log.Errorf("error checking if branding file is used: %v", err)
|
|
// will try again with the next clean up
|
|
return true
|
|
}
|
|
return used
|
|
}
|
|
|
|
// GetSiteAI get site AI configuration
|
|
func (s *siteInfoCommonService) GetSiteAI(ctx context.Context) (resp *schema.SiteAIResp, err error) {
|
|
resp = &schema.SiteAIResp{}
|
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeAI, resp); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// GetSiteMCP get site AI configuration
|
|
func (s *siteInfoCommonService) GetSiteMCP(ctx context.Context) (resp *schema.SiteMCPResp, err error) {
|
|
resp = &schema.SiteMCPResp{}
|
|
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeMCP, resp); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp, nil
|
|
}
|