Files
wehub-resource-sync 39dbe3a57d
CI / Check and lint (push) Failing after 1s
Lint / Lint (ubuntu-latest) (push) Failing after 1s
chore: import upstream snapshot with attribution
2026-07-13 12:22:32 +08:00

784 lines
24 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
import (
"context"
"encoding/json"
errpkg "errors"
"fmt"
"strings"
"github.com/apache/answer/internal/base/constant"
"github.com/apache/answer/internal/base/handler"
"github.com/apache/answer/internal/base/reason"
"github.com/apache/answer/internal/base/translator"
"github.com/apache/answer/internal/entity"
"github.com/apache/answer/internal/schema"
"github.com/apache/answer/internal/service/config"
"github.com/apache/answer/internal/service/export"
"github.com/apache/answer/internal/service/file_record"
questioncommon "github.com/apache/answer/internal/service/question_common"
"github.com/apache/answer/internal/service/siteinfo_common"
tagcommon "github.com/apache/answer/internal/service/tag_common"
"github.com/apache/answer/plugin"
"github.com/go-resty/resty/v2"
"github.com/jinzhu/copier"
"github.com/segmentfault/pacman/errors"
"github.com/segmentfault/pacman/log"
)
type SiteInfoService struct {
siteInfoRepo siteinfo_common.SiteInfoRepo
siteInfoCommonService siteinfo_common.SiteInfoCommonService
emailService *export.EmailService
tagCommonService *tagcommon.TagCommonService
configService *config.ConfigService
questioncommon *questioncommon.QuestionCommon
fileRecordService *file_record.FileRecordService
}
func NewSiteInfoService(
siteInfoRepo siteinfo_common.SiteInfoRepo,
siteInfoCommonService siteinfo_common.SiteInfoCommonService,
emailService *export.EmailService,
tagCommonService *tagcommon.TagCommonService,
configService *config.ConfigService,
questioncommon *questioncommon.QuestionCommon,
fileRecordService *file_record.FileRecordService,
) *SiteInfoService {
plugin.RegisterGetSiteURLFunc(func() string {
generalSiteInfo, err := siteInfoCommonService.GetSiteGeneral(context.Background())
if err != nil {
log.Error(err)
return ""
}
return generalSiteInfo.SiteUrl
})
return &SiteInfoService{
siteInfoRepo: siteInfoRepo,
siteInfoCommonService: siteInfoCommonService,
emailService: emailService,
tagCommonService: tagCommonService,
configService: configService,
questioncommon: questioncommon,
fileRecordService: fileRecordService,
}
}
// GetSiteGeneral get site info general
func (s *SiteInfoService) GetSiteGeneral(ctx context.Context) (resp *schema.SiteGeneralResp, err error) {
return s.siteInfoCommonService.GetSiteGeneral(ctx)
}
// GetSiteInterface get site info interface
func (s *SiteInfoService) GetSiteInterface(ctx context.Context) (resp *schema.SiteInterfaceSettingsResp, err error) {
return s.siteInfoCommonService.GetSiteInterface(ctx)
}
// GetSiteUsersSettings get site info users settings
func (s *SiteInfoService) GetSiteUsersSettings(ctx context.Context) (resp *schema.SiteUsersSettingsResp, err error) {
return s.siteInfoCommonService.GetSiteUsersSettings(ctx)
}
// GetSiteBranding get site info branding
func (s *SiteInfoService) GetSiteBranding(ctx context.Context) (resp *schema.SiteBrandingResp, err error) {
return s.siteInfoCommonService.GetSiteBranding(ctx)
}
// GetSiteUsers get site info about users
func (s *SiteInfoService) GetSiteUsers(ctx context.Context) (resp *schema.SiteUsersResp, err error) {
return s.siteInfoCommonService.GetSiteUsers(ctx)
}
// GetSiteTag get site info write
func (s *SiteInfoService) GetSiteTag(ctx context.Context) (resp *schema.SiteTagsResp, err error) {
resp, err = s.siteInfoCommonService.GetSiteTag(ctx)
if err != nil {
log.Error(err)
return resp, nil
}
resp.RecommendTags, err = s.tagCommonService.GetSiteWriteRecommendTag(ctx)
if err != nil {
log.Error(err)
}
resp.ReservedTags, err = s.tagCommonService.GetSiteWriteReservedTag(ctx)
if err != nil {
log.Error(err)
}
return resp, nil
}
// GetSiteQuestion get site questions settings
func (s *SiteInfoService) GetSiteQuestion(ctx context.Context) (resp *schema.SiteQuestionsResp, err error) {
return s.siteInfoCommonService.GetSiteQuestion(ctx)
}
// GetSiteAdvanced get site advanced settings
func (s *SiteInfoService) GetSiteAdvanced(ctx context.Context) (resp *schema.SiteAdvancedResp, err error) {
return s.siteInfoCommonService.GetSiteAdvanced(ctx)
}
// GetSitePolicies get site legal info
func (s *SiteInfoService) GetSitePolicies(ctx context.Context) (resp *schema.SitePoliciesResp, err error) {
return s.siteInfoCommonService.GetSitePolicies(ctx)
}
// GetSiteSecurity get site security info
func (s *SiteInfoService) GetSiteSecurity(ctx context.Context) (resp *schema.SiteSecurityResp, err error) {
return s.siteInfoCommonService.GetSiteSecurity(ctx)
}
// GetSiteLogin get site login info
func (s *SiteInfoService) GetSiteLogin(ctx context.Context) (resp *schema.SiteLoginResp, err error) {
return s.siteInfoCommonService.GetSiteLogin(ctx)
}
// GetSiteCustomCssHTML get site custom css html config
func (s *SiteInfoService) GetSiteCustomCssHTML(ctx context.Context) (resp *schema.SiteCustomCssHTMLResp, err error) {
return s.siteInfoCommonService.GetSiteCustomCssHTML(ctx)
}
// GetSiteTheme get site theme config
func (s *SiteInfoService) GetSiteTheme(ctx context.Context) (resp *schema.SiteThemeResp, err error) {
return s.siteInfoCommonService.GetSiteTheme(ctx)
}
func (s *SiteInfoService) SaveSiteGeneral(ctx context.Context, req schema.SiteGeneralReq) (err error) {
req.FormatSiteUrl()
content, _ := json.Marshal(req)
data := &entity.SiteInfo{
Type: constant.SiteTypeGeneral,
Content: string(content),
Status: 1,
}
return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeGeneral, data)
}
func (s *SiteInfoService) SaveSiteInterface(ctx context.Context, req schema.SiteInterfaceReq) (err error) {
// If the language is invalid, set it to the default language "en_US"
if !translator.CheckLanguageIsValid(req.Language) {
req.Language = "en_US"
}
content, _ := json.Marshal(req)
data := entity.SiteInfo{
Type: constant.SiteTypeInterfaceSettings,
Content: string(content),
}
return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeInterfaceSettings, &data)
}
// SaveSiteUsersSettings save site users settings
func (s *SiteInfoService) SaveSiteUsersSettings(ctx context.Context, req schema.SiteUsersSettingsReq) (err error) {
content, _ := json.Marshal(req)
data := entity.SiteInfo{
Type: constant.SiteTypeInterfaceSettings,
Content: string(content),
}
return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeUsersSettings, &data)
}
// SaveSiteBranding save site branding information
func (s *SiteInfoService) SaveSiteBranding(ctx context.Context, req *schema.SiteBrandingReq) (err error) {
content, _ := json.Marshal(req)
data := &entity.SiteInfo{
Type: constant.SiteTypeBranding,
Content: string(content),
Status: 1,
}
return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeBranding, data)
}
// SaveSiteAdvanced save site advanced configuration
func (s *SiteInfoService) SaveSiteAdvanced(ctx context.Context, req *schema.SiteAdvancedReq) (resp any, err error) {
content, _ := json.Marshal(req)
data := &entity.SiteInfo{
Type: constant.SiteTypeAdvanced,
Content: string(content),
Status: 1,
}
return nil, s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeAdvanced, data)
}
// SaveSiteQuestions save site questions configuration
func (s *SiteInfoService) SaveSiteQuestions(ctx context.Context, req *schema.SiteQuestionsReq) (resp any, err error) {
content, _ := json.Marshal(req)
data := &entity.SiteInfo{
Type: constant.SiteTypeQuestions,
Content: string(content),
Status: 1,
}
return nil, s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeQuestions, data)
}
// SaveSiteTags save site tags configuration
func (s *SiteInfoService) SaveSiteTags(ctx context.Context, req *schema.SiteTagsReq) (resp any, err error) {
recommendTags, reservedTags := make([]string, 0), make([]string, 0)
recommendTagMapping, reservedTagMapping := make(map[string]bool), make(map[string]bool)
for _, tag := range req.ReservedTags {
if !recommendTagMapping[tag.SlugName] {
reservedTagMapping[tag.SlugName] = true
reservedTags = append(reservedTags, tag.SlugName)
}
}
// recommend tags can't contain reserved tag
for _, tag := range req.RecommendTags {
if reservedTagMapping[tag.SlugName] {
continue
}
if !recommendTagMapping[tag.SlugName] {
recommendTagMapping[tag.SlugName] = true
recommendTags = append(recommendTags, tag.SlugName)
}
}
errData, err := s.tagCommonService.SetSiteWriteTag(ctx, recommendTags, reservedTags, req.UserID)
if err != nil {
return errData, err
}
content, _ := json.Marshal(req)
data := &entity.SiteInfo{
Type: constant.SiteTypeTags,
Content: string(content),
Status: 1,
}
return nil, s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeTags, data)
}
// SaveSitePolicies save site policies configuration
func (s *SiteInfoService) SaveSitePolicies(ctx context.Context, req *schema.SitePoliciesReq) (err error) {
content, _ := json.Marshal(req)
data := &entity.SiteInfo{
Type: constant.SiteTypePolicies,
Content: string(content),
Status: 1,
}
return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypePolicies, data)
}
// SaveSiteSecurity save site security configuration
func (s *SiteInfoService) SaveSiteSecurity(ctx context.Context, req *schema.SiteSecurityReq) (err error) {
content, _ := json.Marshal(req)
data := &entity.SiteInfo{
Type: constant.SiteTypeSecurity,
Content: string(content),
Status: 1,
}
return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeSecurity, data)
}
// SaveSiteLogin save site legal configuration
func (s *SiteInfoService) SaveSiteLogin(ctx context.Context, req *schema.SiteLoginReq) (err error) {
if req.RequireEmailVerification == nil {
return errors.BadRequest(reason.RequestFormatError)
}
loginConfig := &schema.SiteLoginResp{
AllowNewRegistrations: req.AllowNewRegistrations,
AllowEmailRegistrations: req.AllowEmailRegistrations,
AllowPasswordLogin: req.AllowPasswordLogin,
AllowEmailDomains: req.AllowEmailDomains,
RequireEmailVerification: *req.RequireEmailVerification,
}
content, _ := json.Marshal(loginConfig)
data := &entity.SiteInfo{
Type: constant.SiteTypeLogin,
Content: string(content),
Status: 1,
}
return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeLogin, data)
}
// SaveSiteCustomCssHTML save site custom html configuration
func (s *SiteInfoService) SaveSiteCustomCssHTML(ctx context.Context, req *schema.SiteCustomCssHTMLReq) (err error) {
content, _ := json.Marshal(req)
data := &entity.SiteInfo{
Type: constant.SiteTypeCustomCssHTML,
Content: string(content),
Status: 1,
}
return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeCustomCssHTML, data)
}
// SaveSiteTheme save site custom html configuration
func (s *SiteInfoService) SaveSiteTheme(ctx context.Context, req *schema.SiteThemeReq) (err error) {
if len(req.Layout) == 0 {
req.Layout = constant.ThemeLayoutFullWidth
}
content, _ := json.Marshal(req)
data := &entity.SiteInfo{
Type: constant.SiteTypeTheme,
Content: string(content),
Status: 1,
}
return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeTheme, data)
}
// SaveSiteUsers save site users
func (s *SiteInfoService) SaveSiteUsers(ctx context.Context, req *schema.SiteUsersReq) (err error) {
content, _ := json.Marshal(req)
data := &entity.SiteInfo{
Type: constant.SiteTypeUsers,
Content: string(content),
Status: 1,
}
return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeUsers, data)
}
// GetSiteAI get site AI configuration
func (s *SiteInfoService) GetSiteAI(ctx context.Context) (resp *schema.SiteAIResp, err error) {
resp, err = s.siteInfoCommonService.GetSiteAI(ctx)
if err != nil {
return nil, err
}
aiProvider, err := s.GetAIProvider(ctx)
if err != nil {
return nil, err
}
providerMapping := make(map[string]*schema.SiteAIProvider)
for _, provider := range resp.SiteAIProviders {
providerMapping[provider.Provider] = provider
}
providers := make([]*schema.SiteAIProvider, 0)
for _, p := range aiProvider {
if provider, ok := providerMapping[p.Name]; ok {
providers = append(providers, provider)
} else {
providers = append(providers, &schema.SiteAIProvider{
Provider: p.Name,
})
}
}
resp.SiteAIProviders = providers
s.maskAIKeys(resp)
return resp, nil
}
// SaveSiteAI save site AI configuration
func (s *SiteInfoService) SaveSiteAI(ctx context.Context, req *schema.SiteAIReq) (err error) {
if err := s.restoreMaskedAIKeys(ctx, req); err != nil {
return err
}
if req.PromptConfig == nil {
req.PromptConfig = &schema.AIPromptConfig{
ZhCN: constant.DefaultAIPromptConfigZhCN,
EnUS: constant.DefaultAIPromptConfigEnUS,
}
}
aiProvider, err := s.GetAIProvider(ctx)
if err != nil {
return err
}
providerMapping := make(map[string]*schema.SiteAIProvider)
for _, provider := range req.SiteAIProviders {
providerMapping[provider.Provider] = provider
}
providers := make([]*schema.SiteAIProvider, 0)
for _, p := range aiProvider {
if provider, ok := providerMapping[p.Name]; ok {
if len(provider.APIHost) == 0 && provider.Provider == req.ChosenProvider {
provider.APIHost = p.DefaultAPIHost
}
providers = append(providers, provider)
} else {
providers = append(providers, &schema.SiteAIProvider{
Provider: p.Name,
APIHost: p.DefaultAPIHost,
})
}
}
req.SiteAIProviders = providers
content, _ := json.Marshal(req)
siteInfo := &entity.SiteInfo{
Type: constant.SiteTypeAI,
Content: string(content),
Status: 1,
}
return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeAI, siteInfo)
}
func (s *SiteInfoService) maskAIKeys(resp *schema.SiteAIResp) {
for _, provider := range resp.SiteAIProviders {
if provider.APIKey == "" {
continue
}
provider.APIKey = strings.Repeat("*", len(provider.APIKey))
}
}
func (s *SiteInfoService) restoreMaskedAIKeys(ctx context.Context, req *schema.SiteAIReq) error {
hasMasked := false
for _, provider := range req.SiteAIProviders {
if provider.APIKey != "" && isAllMask(provider.APIKey) {
hasMasked = true
break
}
}
if !hasMasked {
return nil
}
current, err := s.siteInfoCommonService.GetSiteAI(ctx)
if err != nil {
return err
}
currentMapping := make(map[string]*schema.SiteAIProvider)
for _, provider := range current.SiteAIProviders {
currentMapping[provider.Provider] = provider
}
for _, provider := range req.SiteAIProviders {
if provider.APIKey == "" || !isAllMask(provider.APIKey) {
continue
}
if stored, ok := currentMapping[provider.Provider]; ok {
provider.APIKey = stored.APIKey
}
}
return nil
}
func isAllMask(value string) bool {
return strings.Trim(value, "*") == ""
}
// GetSiteMCP get site MCP configuration
func (s *SiteInfoService) GetSiteMCP(ctx context.Context) (resp *schema.SiteMCPResp, err error) {
resp, err = s.siteInfoCommonService.GetSiteMCP(ctx)
if err != nil {
return nil, err
}
siteInfo, err := s.GetSiteGeneral(ctx)
if err != nil {
return nil, err
}
resp.Type = "Server-Sent Event (SSE)"
resp.URL = fmt.Sprintf("%s/answer/api/v1/mcp/sse", siteInfo.SiteUrl)
resp.HTTPHeader = "Authorization={key}"
return
}
// SaveSiteMCP save site MCP configuration
func (s *SiteInfoService) SaveSiteMCP(ctx context.Context, req *schema.SiteMCPReq) (err error) {
content, _ := json.Marshal(req)
siteInfo := &entity.SiteInfo{
Type: constant.SiteTypeMCP,
Content: string(content),
Status: 1,
}
return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeMCP, siteInfo)
}
// GetSMTPConfig get smtp config
func (s *SiteInfoService) GetSMTPConfig(ctx context.Context) (resp *schema.GetSMTPConfigResp, err error) {
emailConfig, err := s.emailService.GetEmailConfig(ctx)
if err != nil {
return nil, err
}
resp = &schema.GetSMTPConfigResp{}
_ = copier.Copy(resp, emailConfig)
resp.SMTPPassword = strings.Repeat("*", len(resp.SMTPPassword))
return resp, nil
}
// UpdateSMTPConfig get smtp config
func (s *SiteInfoService) UpdateSMTPConfig(ctx context.Context, req *schema.UpdateSMTPConfigReq) (err error) {
emailConfig, err := s.emailService.GetEmailConfig(ctx)
if err != nil {
return err
}
ec := &export.EmailConfig{}
_ = copier.Copy(ec, req)
if len(ec.SMTPPassword) > 0 && ec.SMTPPassword == strings.Repeat("*", len(ec.SMTPPassword)) {
ec.SMTPPassword = emailConfig.SMTPPassword
}
err = s.emailService.SetEmailConfig(ctx, ec)
if err != nil {
return err
}
if len(req.TestEmailRecipient) > 0 {
title, body, err := s.emailService.TestTemplate(ctx)
if err != nil {
return err
}
go s.emailService.Send(ctx, req.TestEmailRecipient, title, body)
}
return nil
}
func (s *SiteInfoService) GetSeo(ctx context.Context) (resp *schema.SiteSeoReq, err error) {
resp = &schema.SiteSeoReq{}
if err = s.siteInfoCommonService.GetSiteInfoByType(ctx, constant.SiteTypeSeo, resp); err != nil {
return resp, err
}
siteSecurity, err := s.GetSiteSecurity(ctx)
if err != nil {
log.Error(err)
return resp, nil
}
// If the site is set to privacy mode, prohibit crawling any page.
if siteSecurity.LoginRequired {
resp.Robots = "User-agent: *\nDisallow: /"
return resp, nil
}
return resp, nil
}
func (s *SiteInfoService) SaveSeo(ctx context.Context, req schema.SiteSeoReq) (err error) {
content, _ := json.Marshal(req)
data := entity.SiteInfo{
Type: constant.SiteTypeSeo,
Content: string(content),
}
return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeSeo, &data)
}
func (s *SiteInfoService) GetPrivilegesConfig(ctx context.Context) (resp *schema.GetPrivilegesConfigResp, err error) {
privilege := &schema.UpdatePrivilegesConfigReq{}
if err = s.siteInfoCommonService.GetSiteInfoByType(ctx, constant.SiteTypePrivileges, privilege); err != nil {
return nil, err
}
privilegeOptions := schema.DefaultPrivilegeOptions
if len(privilege.CustomPrivileges) > 0 {
privilegeOptions = append(privilegeOptions, &schema.PrivilegeOption{
Level: schema.PrivilegeLevelCustom,
LevelDesc: reason.PrivilegeLevelCustomDesc,
Privileges: privilege.CustomPrivileges,
})
} else {
privilegeOptions = append(privilegeOptions, schema.DefaultCustomPrivilegeOption)
}
resp = &schema.GetPrivilegesConfigResp{
Options: s.translatePrivilegeOptions(ctx, privilegeOptions),
SelectedLevel: schema.PrivilegeLevel3,
}
if privilege.Level > 0 {
resp.SelectedLevel = privilege.Level
}
return resp, nil
}
func (s *SiteInfoService) translatePrivilegeOptions(ctx context.Context, privilegeOptions []*schema.PrivilegeOption) (options []*schema.PrivilegeOption) {
la := handler.GetLangByCtx(ctx)
for _, option := range privilegeOptions {
op := &schema.PrivilegeOption{
Level: option.Level,
LevelDesc: translator.Tr(la, option.LevelDesc),
}
for _, privilege := range option.Privileges {
op.Privileges = append(op.Privileges, &constant.Privilege{
Key: privilege.Key,
Label: translator.Tr(la, privilege.Label),
Value: privilege.Value,
})
}
options = append(options, op)
}
return
}
func (s *SiteInfoService) UpdatePrivilegesConfig(ctx context.Context, req *schema.UpdatePrivilegesConfigReq) (err error) {
var choosePrivileges []*constant.Privilege
if req.Level == schema.PrivilegeLevelCustom {
choosePrivileges = req.CustomPrivileges
} else {
chooseOption := schema.DefaultPrivilegeOptions.Choose(req.Level)
if chooseOption == nil {
return nil
}
choosePrivileges = chooseOption.Privileges
}
if choosePrivileges == nil {
return nil
}
// update site info that user choose which privilege level
if req.Level == schema.PrivilegeLevelCustom {
privilegeMap := make(map[string]int)
for _, privilege := range req.CustomPrivileges {
privilegeMap[privilege.Key] = privilege.Value
}
var privileges []*constant.Privilege
for _, privilege := range constant.RankAllPrivileges {
privileges = append(privileges, &constant.Privilege{
Key: privilege.Key,
Label: privilege.Label,
Value: privilegeMap[privilege.Key],
})
}
req.CustomPrivileges = privileges
} else {
privilege := &schema.UpdatePrivilegesConfigReq{}
if err = s.siteInfoCommonService.GetSiteInfoByType(ctx, constant.SiteTypePrivileges, privilege); err != nil {
return err
}
req.CustomPrivileges = privilege.CustomPrivileges
}
content, _ := json.Marshal(req)
data := &entity.SiteInfo{
Type: constant.SiteTypePrivileges,
Content: string(content),
Status: 1,
}
err = s.siteInfoRepo.SaveByType(ctx, constant.SiteTypePrivileges, data)
if err != nil {
return err
}
// update privilege in config
for _, privilege := range choosePrivileges {
err = s.configService.UpdateConfig(ctx, privilege.Key, fmt.Sprintf("%d", privilege.Value))
if err != nil {
return err
}
}
return
}
func (s *SiteInfoService) CleanUpRemovedBrandingFiles(
ctx context.Context,
newBranding *schema.SiteBrandingReq,
currentBranding *schema.SiteBrandingResp,
) error {
var allErrors []error
currentFiles := map[string]string{
"logo": currentBranding.Logo,
"mobile_logo": currentBranding.MobileLogo,
"square_icon": currentBranding.SquareIcon,
"favicon": currentBranding.Favicon,
}
newFiles := map[string]string{
"logo": newBranding.Logo,
"mobile_logo": newBranding.MobileLogo,
"square_icon": newBranding.SquareIcon,
"favicon": newBranding.Favicon,
}
for key, currentFile := range currentFiles {
newFile := newFiles[key]
if currentFile != "" && currentFile != newFile {
fileRecord, err := s.fileRecordService.GetFileRecordByURL(ctx, currentFile)
if err != nil {
allErrors = append(allErrors, err)
continue
}
if fileRecord == nil {
err := errpkg.New("file record is nil for key " + key)
allErrors = append(allErrors, err)
continue
}
if err := s.fileRecordService.DeleteAndMoveFileRecord(ctx, fileRecord); err != nil {
allErrors = append(allErrors, err)
}
}
}
if len(allErrors) > 0 {
return errpkg.Join(allErrors...)
}
return nil
}
func (s *SiteInfoService) GetAIProvider(ctx context.Context) (resp []*schema.GetAIProviderResp, err error) {
resp = make([]*schema.GetAIProviderResp, 0)
aiProviderConfig, err := s.configService.GetStringValue(context.TODO(), constant.AIConfigProvider)
if err != nil {
log.Error(err)
return resp, nil
}
_ = json.Unmarshal([]byte(aiProviderConfig), &resp)
return resp, nil
}
func (s *SiteInfoService) GetAIModels(ctx context.Context, req *schema.GetAIModelsReq) (resp []*schema.GetAIModelResp, err error) {
resp = make([]*schema.GetAIModelResp, 0)
if req.APIKey != "" && isAllMask(req.APIKey) {
storedKey, err := s.getStoredAIKey(ctx, req.APIHost)
if err != nil {
return resp, err
}
if storedKey == "" {
return resp, errors.BadRequest("api_key is required")
}
req.APIKey = storedKey
}
r := resty.New()
r.SetHeader("Authorization", fmt.Sprintf("Bearer %s", req.APIKey))
r.SetHeader("Content-Type", "application/json")
respBody, err := r.R().Get(req.APIHost + "/v1/models")
if err != nil {
log.Error(err)
return resp, errors.BadRequest(fmt.Sprintf("failed to get AI models %s", err.Error()))
}
if !respBody.IsSuccess() {
log.Error(fmt.Sprintf("failed to get AI models, status code: %d, body: %s", respBody.StatusCode(), respBody.String()))
return resp, errors.BadRequest(fmt.Sprintf("failed to get AI models, response: %s", respBody.String()))
}
data := schema.GetAIModelsResp{}
_ = json.Unmarshal(respBody.Body(), &data)
for _, model := range data.Data {
resp = append(resp, &schema.GetAIModelResp{
Id: model.Id,
Object: model.Object,
Created: model.Created,
OwnedBy: model.OwnedBy,
})
}
return resp, nil
}
func (s *SiteInfoService) getStoredAIKey(ctx context.Context, apiHost string) (string, error) {
current, err := s.siteInfoCommonService.GetSiteAI(ctx)
if err != nil {
return "", err
}
apiHost = strings.TrimRight(apiHost, "/")
for _, provider := range current.SiteAIProviders {
if strings.TrimRight(provider.APIHost, "/") == apiHost && provider.APIKey != "" {
return provider.APIKey, nil
}
}
if current.ChosenProvider != "" {
for _, provider := range current.SiteAIProviders {
if provider.Provider == current.ChosenProvider {
return provider.APIKey, nil
}
}
}
return "", nil
}