597 lines
22 KiB
Go
597 lines
22 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 schema
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/mail"
|
|
"net/url"
|
|
"path/filepath"
|
|
"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/base/validator"
|
|
"github.com/segmentfault/pacman/errors"
|
|
)
|
|
|
|
// SiteGeneralReq site general request
|
|
type SiteGeneralReq struct {
|
|
Name string `validate:"required,sanitizer,gt=1,lte=128" form:"name" json:"name"`
|
|
ShortDescription string `validate:"omitempty,sanitizer,gt=3,lte=255" form:"short_description" json:"short_description"`
|
|
Description string `validate:"omitempty,sanitizer,gt=3,lte=2000" form:"description" json:"description"`
|
|
SiteUrl string `validate:"required,sanitizer,gt=1,lte=512,url" form:"site_url" json:"site_url"`
|
|
ContactEmail string `validate:"required,sanitizer,gt=1,lte=512,email" form:"contact_email" json:"contact_email"`
|
|
}
|
|
|
|
func (r *SiteGeneralReq) FormatSiteUrl() {
|
|
parsedUrl, err := url.Parse(r.SiteUrl)
|
|
if err != nil {
|
|
return
|
|
}
|
|
r.SiteUrl = fmt.Sprintf("%s://%s", parsedUrl.Scheme, parsedUrl.Host)
|
|
if len(parsedUrl.Path) > 0 {
|
|
r.SiteUrl += parsedUrl.Path
|
|
r.SiteUrl = strings.TrimSuffix(r.SiteUrl, "/")
|
|
}
|
|
}
|
|
|
|
// SiteInterfaceReq site interface request
|
|
type SiteInterfaceReq struct {
|
|
Language string `validate:"required,gt=1,lte=128" form:"language" json:"language"`
|
|
TimeZone string `validate:"required,gt=1,lte=128" form:"time_zone" json:"time_zone"`
|
|
// Deperecated: use SiteUsersSettingsReq instead
|
|
DefaultAvatar string `validate:"omitempty" json:"-"`
|
|
// Deperecated: use SiteUsersSettingsReq instead
|
|
GravatarBaseURL string `validate:"omitempty" json:"-"`
|
|
}
|
|
|
|
// SiteInterfaceSettingsReq site interface settings request
|
|
type SiteInterfaceSettingsReq struct {
|
|
Language string `validate:"required,gt=1,lte=128" json:"language"`
|
|
TimeZone string `validate:"required,gt=1,lte=128" json:"time_zone"`
|
|
}
|
|
|
|
type SiteInterfaceSettingsResp SiteInterfaceSettingsReq
|
|
|
|
type SiteUsersSettingsReq struct {
|
|
DefaultAvatar string `validate:"required,oneof=system gravatar" json:"default_avatar"`
|
|
GravatarBaseURL string `validate:"omitempty" json:"gravatar_base_url"`
|
|
}
|
|
|
|
type SiteUsersSettingsResp SiteUsersSettingsReq
|
|
|
|
// SiteBrandingReq site branding request
|
|
type SiteBrandingReq struct {
|
|
Logo string `validate:"omitempty,gt=0,lte=512" form:"logo" json:"logo"`
|
|
MobileLogo string `validate:"omitempty,gt=0,lte=512" form:"mobile_logo" json:"mobile_logo"`
|
|
SquareIcon string `validate:"omitempty,gt=0,lte=512" form:"square_icon" json:"square_icon"`
|
|
Favicon string `validate:"omitempty,gt=0,lte=512" form:"favicon" json:"favicon"`
|
|
}
|
|
|
|
// SiteWriteReq site write request use SiteQuestionsReq, SiteAdvancedReq and SiteTagsReq instead
|
|
type SiteWriteReq struct {
|
|
MinimumContent int `validate:"omitempty,gte=0,lte=65535" json:"min_content"`
|
|
RestrictAnswer bool `validate:"omitempty" json:"restrict_answer"`
|
|
MinimumTags int `validate:"omitempty,gte=0,lte=5" json:"min_tags"`
|
|
RequiredTag bool `validate:"omitempty" json:"required_tag"`
|
|
RecommendTags []*SiteWriteTag `validate:"omitempty,dive" json:"recommend_tags"`
|
|
ReservedTags []*SiteWriteTag `validate:"omitempty,dive" json:"reserved_tags"`
|
|
MaxImageSize int `validate:"omitempty,gt=0" json:"max_image_size"`
|
|
MaxAttachmentSize int `validate:"omitempty,gt=0" json:"max_attachment_size"`
|
|
MaxImageMegapixel int `validate:"omitempty,gt=0" json:"max_image_megapixel"`
|
|
AuthorizedImageExtensions []string `validate:"omitempty" json:"authorized_image_extensions"`
|
|
AuthorizedAttachmentExtensions []string `validate:"omitempty" json:"authorized_attachment_extensions"`
|
|
UserID string `json:"-"`
|
|
}
|
|
|
|
type SiteWriteResp SiteWriteReq
|
|
|
|
// SiteQuestionsReq site questions settings request
|
|
type SiteQuestionsReq struct {
|
|
MinimumTags int `validate:"omitempty,gte=0,lte=5" json:"min_tags"`
|
|
MinimumContent int `validate:"omitempty,gte=0,lte=65535" json:"min_content"`
|
|
RestrictAnswer bool `validate:"omitempty" json:"restrict_answer"`
|
|
}
|
|
|
|
// SiteAdvancedReq site advanced settings request
|
|
type SiteAdvancedReq struct {
|
|
MaxImageSize int `validate:"omitempty,gt=0" json:"max_image_size"`
|
|
MaxAttachmentSize int `validate:"omitempty,gt=0" json:"max_attachment_size"`
|
|
MaxImageMegapixel int `validate:"omitempty,gt=0" json:"max_image_megapixel"`
|
|
AuthorizedImageExtensions []string `validate:"omitempty" json:"authorized_image_extensions"`
|
|
AuthorizedAttachmentExtensions []string `validate:"omitempty" json:"authorized_attachment_extensions"`
|
|
}
|
|
|
|
// SiteTagsReq site tags settings request
|
|
type SiteTagsReq struct {
|
|
ReservedTags []*SiteWriteTag `validate:"omitempty,dive" json:"reserved_tags"`
|
|
RecommendTags []*SiteWriteTag `validate:"omitempty,dive" json:"recommend_tags"`
|
|
RequiredTag bool `validate:"omitempty" json:"required_tag"`
|
|
UserID string `json:"-"`
|
|
}
|
|
|
|
func (s *SiteAdvancedResp) GetMaxImageSize() int64 {
|
|
if s.MaxImageSize <= 0 {
|
|
return constant.DefaultMaxImageSize
|
|
}
|
|
return int64(s.MaxImageSize) * 1024 * 1024
|
|
}
|
|
|
|
func (s *SiteAdvancedResp) GetMaxAttachmentSize() int64 {
|
|
if s.MaxAttachmentSize <= 0 {
|
|
return constant.DefaultMaxAttachmentSize
|
|
}
|
|
return int64(s.MaxAttachmentSize) * 1024 * 1024
|
|
}
|
|
|
|
func (s *SiteAdvancedResp) GetMaxImageMegapixel() int {
|
|
if s.MaxImageMegapixel <= 0 {
|
|
return constant.DefaultMaxImageMegapixel
|
|
}
|
|
return s.MaxImageMegapixel * 1000 * 1000
|
|
}
|
|
|
|
// SiteWriteTag site write response tag
|
|
type SiteWriteTag struct {
|
|
SlugName string `validate:"required" json:"slug_name"`
|
|
DisplayName string `json:"display_name"`
|
|
}
|
|
|
|
// SiteLegalReq site branding request use SitePoliciesReq and SiteSecurityReq instead
|
|
type SiteLegalReq struct {
|
|
TermsOfServiceOriginalText string `json:"terms_of_service_original_text"`
|
|
TermsOfServiceParsedText string `json:"terms_of_service_parsed_text"`
|
|
PrivacyPolicyOriginalText string `json:"privacy_policy_original_text"`
|
|
PrivacyPolicyParsedText string `json:"privacy_policy_parsed_text"`
|
|
ExternalContentDisplay string `validate:"required,oneof=always_display ask_before_display" json:"external_content_display"`
|
|
}
|
|
|
|
type SitePoliciesReq struct {
|
|
TermsOfServiceOriginalText string `json:"terms_of_service_original_text"`
|
|
TermsOfServiceParsedText string `json:"terms_of_service_parsed_text"`
|
|
PrivacyPolicyOriginalText string `json:"privacy_policy_original_text"`
|
|
PrivacyPolicyParsedText string `json:"privacy_policy_parsed_text"`
|
|
}
|
|
|
|
type SiteSecurityReq struct {
|
|
LoginRequired bool `json:"login_required"`
|
|
ExternalContentDisplay string `validate:"required,oneof=always_display ask_before_display" json:"external_content_display"`
|
|
CheckUpdate bool `validate:"omitempty,sanitizer" form:"check_update" json:"check_update"`
|
|
}
|
|
|
|
type SitePoliciesResp SitePoliciesReq
|
|
type SiteSecurityResp SiteSecurityReq
|
|
|
|
// GetSiteLegalInfoReq site site legal request
|
|
type GetSiteLegalInfoReq struct {
|
|
InfoType string `validate:"required,oneof=tos privacy" form:"info_type"`
|
|
}
|
|
|
|
func (r *GetSiteLegalInfoReq) IsTOS() bool {
|
|
return r.InfoType == "tos"
|
|
}
|
|
|
|
func (r *GetSiteLegalInfoReq) IsPrivacy() bool {
|
|
return r.InfoType == "privacy"
|
|
}
|
|
|
|
// GetSiteLegalInfoResp get site legal info response
|
|
type GetSiteLegalInfoResp struct {
|
|
TermsOfServiceOriginalText string `json:"terms_of_service_original_text,omitempty"`
|
|
TermsOfServiceParsedText string `json:"terms_of_service_parsed_text,omitempty"`
|
|
PrivacyPolicyOriginalText string `json:"privacy_policy_original_text,omitempty"`
|
|
PrivacyPolicyParsedText string `json:"privacy_policy_parsed_text,omitempty"`
|
|
}
|
|
|
|
// SiteUsersReq site users config request
|
|
type SiteUsersReq struct {
|
|
DefaultAvatar string `validate:"required,oneof=system gravatar" json:"default_avatar"`
|
|
GravatarBaseURL string `json:"gravatar_base_url"`
|
|
AllowUpdateDisplayName bool `json:"allow_update_display_name"`
|
|
AllowUpdateUsername bool `json:"allow_update_username"`
|
|
AllowUpdateAvatar bool `json:"allow_update_avatar"`
|
|
AllowUpdateBio bool `json:"allow_update_bio"`
|
|
AllowUpdateWebsite bool `json:"allow_update_website"`
|
|
AllowUpdateLocation bool `json:"allow_update_location"`
|
|
}
|
|
|
|
// SiteLoginReq site login request
|
|
type SiteLoginReq struct {
|
|
AllowNewRegistrations bool `json:"allow_new_registrations"`
|
|
AllowEmailRegistrations bool `json:"allow_email_registrations"`
|
|
AllowPasswordLogin bool `json:"allow_password_login"`
|
|
AllowEmailDomains []string `json:"allow_email_domains"`
|
|
RequireEmailVerification *bool `validate:"required" json:"require_email_verification" swaggertype:"boolean"`
|
|
}
|
|
|
|
// SiteLoginResp site login response
|
|
type SiteLoginResp struct {
|
|
AllowNewRegistrations bool `json:"allow_new_registrations"`
|
|
AllowEmailRegistrations bool `json:"allow_email_registrations"`
|
|
AllowPasswordLogin bool `json:"allow_password_login"`
|
|
AllowEmailDomains []string `json:"allow_email_domains"`
|
|
RequireEmailVerification bool `json:"require_email_verification"`
|
|
}
|
|
|
|
// SiteCustomCssHTMLReq site custom css html
|
|
type SiteCustomCssHTMLReq struct {
|
|
CustomHead string `validate:"omitempty,gt=0,lte=65536" json:"custom_head"`
|
|
CustomCss string `validate:"omitempty,gt=0,lte=65536" json:"custom_css"`
|
|
CustomHeader string `validate:"omitempty,gt=0,lte=65536" json:"custom_header"`
|
|
CustomFooter string `validate:"omitempty,gt=0,lte=65536" json:"custom_footer"`
|
|
CustomSideBar string `validate:"omitempty,gt=0,lte=65536" json:"custom_sidebar"`
|
|
}
|
|
|
|
// SiteThemeReq site theme config
|
|
type SiteThemeReq struct {
|
|
Theme string `validate:"required,gt=0,lte=255" json:"theme"`
|
|
ThemeConfig map[string]any `validate:"omitempty" json:"theme_config"`
|
|
ColorScheme string `validate:"omitempty,gt=0,lte=100" json:"color_scheme"`
|
|
Layout string `validate:"omitempty,oneof=Full-width Fixed-width" json:"layout"`
|
|
}
|
|
|
|
type SiteSeoReq struct {
|
|
Permalink int `validate:"required,lte=4,gte=0" form:"permalink" json:"permalink"`
|
|
Robots string `validate:"required" form:"robots" json:"robots"`
|
|
}
|
|
|
|
func (s *SiteSeoResp) IsShortLink() bool {
|
|
return s.Permalink == constant.PermalinkQuestionIDAndTitleByShortID ||
|
|
s.Permalink == constant.PermalinkQuestionIDByShortID
|
|
}
|
|
|
|
// AIPromptConfig AI prompt configuration for different languages
|
|
type AIPromptConfig struct {
|
|
ZhCN string `json:"zh_cn"`
|
|
EnUS string `json:"en_us"`
|
|
}
|
|
|
|
// SiteAIReq AI configuration request
|
|
type SiteAIReq struct {
|
|
Enabled bool `validate:"omitempty" form:"enabled" json:"enabled"`
|
|
ChosenProvider string `validate:"omitempty,lte=50" form:"chosen_provider" json:"chosen_provider"`
|
|
SiteAIProviders []*SiteAIProvider `validate:"omitempty,dive" form:"ai_providers" json:"ai_providers"`
|
|
PromptConfig *AIPromptConfig `validate:"omitempty" form:"prompt_config" json:"prompt_config,omitempty"`
|
|
}
|
|
|
|
func (s *SiteAIResp) GetProvider() *SiteAIProvider {
|
|
if !s.Enabled || s.ChosenProvider == "" {
|
|
return &SiteAIProvider{}
|
|
}
|
|
if len(s.SiteAIProviders) == 0 {
|
|
return &SiteAIProvider{}
|
|
}
|
|
for _, provider := range s.SiteAIProviders {
|
|
if provider.Provider == s.ChosenProvider {
|
|
return provider
|
|
}
|
|
}
|
|
return &SiteAIProvider{}
|
|
}
|
|
|
|
type SiteAIProvider struct {
|
|
Provider string `validate:"omitempty,lte=50" form:"provider" json:"provider"`
|
|
APIHost string `validate:"omitempty,lte=512" form:"api_host" json:"api_host"`
|
|
APIKey string `validate:"omitempty,lte=256" form:"api_key" json:"api_key"`
|
|
Model string `validate:"omitempty,lte=100" form:"model" json:"model"`
|
|
}
|
|
|
|
// SiteAIResp AI configuration response
|
|
type SiteAIResp SiteAIReq
|
|
|
|
type SiteMCPReq struct {
|
|
Enabled bool `validate:"omitempty" form:"enabled" json:"enabled"`
|
|
}
|
|
|
|
type SiteMCPResp struct {
|
|
Enabled bool `json:"enabled"`
|
|
Type string `json:"type"`
|
|
URL string `json:"url"`
|
|
HTTPHeader string `json:"http_header"`
|
|
}
|
|
|
|
// SiteGeneralResp site general response
|
|
type SiteGeneralResp SiteGeneralReq
|
|
|
|
// SiteInterfaceResp site interface response
|
|
type SiteInterfaceResp SiteInterfaceReq
|
|
|
|
// SiteBrandingResp site branding response
|
|
type SiteBrandingResp SiteBrandingReq
|
|
|
|
// SiteCustomCssHTMLResp site custom css html response
|
|
type SiteCustomCssHTMLResp SiteCustomCssHTMLReq
|
|
|
|
// SiteUsersResp site users response
|
|
type SiteUsersResp SiteUsersReq
|
|
|
|
// SiteThemeResp site theme response
|
|
type SiteThemeResp struct {
|
|
ThemeOptions []*ThemeOption `json:"theme_options"`
|
|
Theme string `json:"theme"`
|
|
ThemeConfig map[string]any `json:"theme_config"`
|
|
ColorScheme string `json:"color_scheme"`
|
|
Layout string `json:"layout"`
|
|
}
|
|
|
|
func (s *SiteThemeResp) TrTheme(ctx context.Context) {
|
|
la := handler.GetLangByCtx(ctx)
|
|
for _, option := range s.ThemeOptions {
|
|
tr := translator.Tr(la, option.Value)
|
|
// if tr is equal the option value means not found translation, so use the original label
|
|
if tr != option.Value {
|
|
option.Label = tr
|
|
}
|
|
}
|
|
}
|
|
|
|
// ThemeOption get label option
|
|
type ThemeOption struct {
|
|
Label string `json:"label"`
|
|
Value string `json:"value"`
|
|
}
|
|
|
|
type SiteQuestionsResp SiteQuestionsReq
|
|
type SiteAdvancedResp SiteAdvancedReq
|
|
type SiteTagsResp SiteTagsReq
|
|
|
|
// SiteLegalResp site write response use SitePoliciesResp and SiteSecurityResp instead
|
|
type SiteLegalResp SiteLegalReq
|
|
|
|
// SiteLegalSimpleResp site write response
|
|
type SiteLegalSimpleResp struct {
|
|
ExternalContentDisplay string `validate:"required,oneof=always_display ask_before_display" json:"external_content_display"`
|
|
}
|
|
|
|
// SiteSeoResp site write response
|
|
type SiteSeoResp SiteSeoReq
|
|
|
|
// SiteInfoResp get site info response
|
|
type SiteInfoResp struct {
|
|
General *SiteGeneralResp `json:"general"`
|
|
Interface *SiteInterfaceSettingsResp `json:"interface"`
|
|
UsersSettings *SiteUsersSettingsResp `json:"users_settings"`
|
|
Branding *SiteBrandingResp `json:"branding"`
|
|
Login *SiteLoginResp `json:"login"`
|
|
Theme *SiteThemeResp `json:"theme"`
|
|
CustomCssHtml *SiteCustomCssHTMLResp `json:"custom_css_html"`
|
|
SiteSeo *SiteSeoResp `json:"site_seo"`
|
|
SiteUsers *SiteUsersResp `json:"site_users"`
|
|
Advanced *SiteAdvancedResp `json:"site_advanced"`
|
|
Questions *SiteQuestionsResp `json:"site_questions"`
|
|
Tags *SiteTagsResp `json:"site_tags"`
|
|
Legal *SiteLegalSimpleResp `json:"site_legal"`
|
|
Security *SiteSecurityResp `json:"site_security"`
|
|
Version string `json:"version"`
|
|
Revision string `json:"revision"`
|
|
AIEnabled bool `json:"ai_enabled"`
|
|
MCPEnabled bool `json:"mcp_enabled"`
|
|
}
|
|
|
|
type TemplateSiteInfoResp struct {
|
|
General *SiteGeneralResp `json:"general"`
|
|
Interface *SiteInterfaceSettingsResp `json:"interface"`
|
|
Branding *SiteBrandingResp `json:"branding"`
|
|
SiteSeo *SiteSeoResp `json:"site_seo"`
|
|
CustomCssHtml *SiteCustomCssHTMLResp `json:"custom_css_html"`
|
|
Title string
|
|
Year string
|
|
Canonical string
|
|
JsonLD string
|
|
Keywords string
|
|
Description string
|
|
}
|
|
|
|
// UpdateSMTPConfigReq get smtp config request
|
|
type UpdateSMTPConfigReq struct {
|
|
FromEmail string `validate:"omitempty,gt=0,lte=256" json:"from_email"`
|
|
FromName string `validate:"omitempty,gt=0,lte=256" json:"from_name"`
|
|
SMTPHost string `validate:"omitempty,gt=0,lte=256" json:"smtp_host"`
|
|
SMTPPort int `validate:"omitempty,min=1,max=65535" json:"smtp_port"`
|
|
Encryption string `validate:"omitempty,oneof=SSL TLS" json:"encryption"` // "" SSL TLS
|
|
SMTPUsername string `validate:"omitempty,gt=0,lte=256" json:"smtp_username"`
|
|
SMTPPassword string `validate:"omitempty,gt=0,lte=256" json:"smtp_password"`
|
|
SMTPAuthentication bool `validate:"omitempty" json:"smtp_authentication"`
|
|
TestEmailRecipient string `validate:"omitempty,email" json:"test_email_recipient"`
|
|
}
|
|
|
|
func (r *UpdateSMTPConfigReq) Check() (errField []*validator.FormErrorField, err error) {
|
|
_, err = mail.ParseAddress(r.FromName)
|
|
if err == nil {
|
|
return append(errField, &validator.FormErrorField{
|
|
ErrorField: "from_name",
|
|
ErrorMsg: reason.SMTPConfigFromNameCannotBeEmail,
|
|
}), errors.BadRequest(reason.SMTPConfigFromNameCannotBeEmail)
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
// GetSMTPConfigResp get smtp config response
|
|
type GetSMTPConfigResp struct {
|
|
FromEmail string `json:"from_email"`
|
|
FromName string `json:"from_name"`
|
|
SMTPHost string `json:"smtp_host"`
|
|
SMTPPort int `json:"smtp_port"`
|
|
Encryption string `json:"encryption"` // "" SSL TLS
|
|
SMTPUsername string `json:"smtp_username"`
|
|
SMTPPassword string `json:"smtp_password"`
|
|
SMTPAuthentication bool `json:"smtp_authentication"`
|
|
}
|
|
|
|
// GetManifestJsonResp get manifest json response
|
|
type GetManifestJsonResp struct {
|
|
ManifestVersion int `json:"manifest_version"`
|
|
Version string `json:"version"`
|
|
Revision string `json:"revision"`
|
|
ShortName string `json:"short_name"`
|
|
Name string `json:"name"`
|
|
Icons []ManifestJsonIcon `json:"icons"`
|
|
StartUrl string `json:"start_url"`
|
|
Display string `json:"display"`
|
|
ThemeColor string `json:"theme_color"`
|
|
BackgroundColor string `json:"background_color"`
|
|
}
|
|
|
|
type ManifestJsonIcon struct {
|
|
Src string `json:"src"`
|
|
Sizes string `json:"sizes"`
|
|
Type string `json:"type"`
|
|
}
|
|
|
|
func CreateManifestJsonIcons(icon string) []ManifestJsonIcon {
|
|
ext := filepath.Ext(icon)
|
|
if ext == "" {
|
|
ext = "png"
|
|
} else {
|
|
ext = strings.ToLower(ext[1:])
|
|
}
|
|
iconType := fmt.Sprintf("image/%s", ext)
|
|
return []ManifestJsonIcon{
|
|
{
|
|
Src: icon,
|
|
Sizes: "16x16",
|
|
Type: iconType,
|
|
},
|
|
{
|
|
Src: icon,
|
|
Sizes: "32x32",
|
|
Type: iconType,
|
|
},
|
|
{
|
|
Src: icon,
|
|
Sizes: "48x48",
|
|
Type: iconType,
|
|
},
|
|
{
|
|
Src: icon,
|
|
Sizes: "128x128",
|
|
Type: iconType,
|
|
},
|
|
}
|
|
}
|
|
|
|
const (
|
|
// PrivilegeLevel1 low
|
|
PrivilegeLevel1 PrivilegeLevel = 1
|
|
// PrivilegeLevel2 medium
|
|
PrivilegeLevel2 PrivilegeLevel = 2
|
|
// PrivilegeLevel3 high
|
|
PrivilegeLevel3 PrivilegeLevel = 3
|
|
// PrivilegeLevelCustom custom
|
|
PrivilegeLevelCustom PrivilegeLevel = 99
|
|
)
|
|
|
|
type PrivilegeLevel int
|
|
type PrivilegeOptions []*PrivilegeOption
|
|
|
|
func (p PrivilegeOptions) Choose(level PrivilegeLevel) (option *PrivilegeOption) {
|
|
for _, op := range p {
|
|
if op.Level == level {
|
|
return op
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetPrivilegesConfigResp get privileges config response
|
|
type GetPrivilegesConfigResp struct {
|
|
Options []*PrivilegeOption `json:"options"`
|
|
SelectedLevel PrivilegeLevel `json:"selected_level"`
|
|
}
|
|
|
|
// PrivilegeOption privilege option
|
|
type PrivilegeOption struct {
|
|
Level PrivilegeLevel `json:"level"`
|
|
LevelDesc string `json:"level_desc"`
|
|
Privileges []*constant.Privilege `validate:"dive" json:"privileges"`
|
|
}
|
|
|
|
// UpdatePrivilegesConfigReq update privileges config request
|
|
type UpdatePrivilegesConfigReq struct {
|
|
Level PrivilegeLevel `validate:"required,min=1,max=3|eq=99" json:"level"`
|
|
CustomPrivileges []*constant.Privilege `validate:"dive" json:"custom_privileges"`
|
|
}
|
|
|
|
var (
|
|
DefaultPrivilegeOptions PrivilegeOptions
|
|
DefaultCustomPrivilegeOption *PrivilegeOption
|
|
privilegeOptionsLevelMapping = map[string][]int{
|
|
constant.RankQuestionAddKey: {1, 1, 1},
|
|
constant.RankAnswerAddKey: {1, 1, 1},
|
|
constant.RankCommentAddKey: {1, 1, 1},
|
|
constant.RankReportAddKey: {1, 1, 1},
|
|
constant.RankCommentVoteUpKey: {1, 1, 1},
|
|
constant.RankLinkUrlLimitKey: {1, 10, 10},
|
|
constant.RankQuestionVoteUpKey: {1, 8, 15},
|
|
constant.RankAnswerVoteUpKey: {1, 8, 15},
|
|
constant.RankQuestionVoteDownKey: {125, 125, 125},
|
|
constant.RankAnswerVoteDownKey: {125, 125, 125},
|
|
constant.RankInviteSomeoneToAnswerKey: {1, 500, 1000},
|
|
constant.RankTagAddKey: {1, 750, 1500},
|
|
constant.RankTagEditKey: {1, 50, 100},
|
|
constant.RankQuestionEditKey: {1, 100, 200},
|
|
constant.RankAnswerEditKey: {1, 100, 200},
|
|
constant.RankQuestionEditWithoutReviewKey: {1, 1000, 2000},
|
|
constant.RankAnswerEditWithoutReviewKey: {1, 1000, 2000},
|
|
constant.RankQuestionAuditKey: {1, 1000, 2000},
|
|
constant.RankAnswerAuditKey: {1, 1000, 2000},
|
|
constant.RankTagAuditKey: {1, 2500, 5000},
|
|
constant.RankTagEditWithoutReviewKey: {1, 10000, 20000},
|
|
constant.RankTagSynonymKey: {1, 10000, 20000},
|
|
}
|
|
)
|
|
|
|
func init() {
|
|
DefaultPrivilegeOptions = append(DefaultPrivilegeOptions, &PrivilegeOption{
|
|
Level: PrivilegeLevel1,
|
|
LevelDesc: reason.PrivilegeLevel1Desc,
|
|
}, &PrivilegeOption{
|
|
Level: PrivilegeLevel2,
|
|
LevelDesc: reason.PrivilegeLevel2Desc,
|
|
}, &PrivilegeOption{
|
|
Level: PrivilegeLevel3,
|
|
LevelDesc: reason.PrivilegeLevel3Desc,
|
|
})
|
|
|
|
for _, option := range DefaultPrivilegeOptions {
|
|
for _, privilege := range constant.RankAllPrivileges {
|
|
if len(privilegeOptionsLevelMapping[privilege.Key]) == 0 {
|
|
continue
|
|
}
|
|
option.Privileges = append(option.Privileges, &constant.Privilege{
|
|
Label: privilege.Label,
|
|
Value: privilegeOptionsLevelMapping[privilege.Key][option.Level-1],
|
|
Key: privilege.Key,
|
|
})
|
|
}
|
|
}
|
|
|
|
// set up default custom privilege option
|
|
DefaultCustomPrivilegeOption = &PrivilegeOption{
|
|
Level: PrivilegeLevelCustom,
|
|
LevelDesc: reason.PrivilegeLevelCustomDesc,
|
|
Privileges: DefaultPrivilegeOptions[0].Privileges,
|
|
}
|
|
}
|