refactor: workspace setting definitions

This commit is contained in:
Steven
2024-07-29 22:03:21 +08:00
parent 61d01a53eb
commit ecf77e0774
36 changed files with 1277 additions and 1052 deletions

View File

@ -8,28 +8,28 @@ import (
"strings"
"github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/yourselfhosted/slash/server/version"
)
// Profile is the configuration to start main server.
type Profile struct {
// Mode can be "prod" or "dev"
Mode string `json:"mode"`
// Port is the binding port for server
Port int `json:"-"`
// Data is the data directory
Data string `json:"-"`
// DSN points to where slash stores its own data
DSN string `json:"-"`
// Driver is the database driver
// sqlite, mysql
Driver string `json:"-"`
// Version is the current version of server
Version string `json:"version"`
// Metric indicate the metric collection is enabled or not
Metric bool `json:"-"`
// Mode can be "prod" or "dev".
Mode string
// Port is the binding port for server.
Port int
// Data is the data directory.
Data string
// DSN points to where slash stores its own data.
DSN string
// Driver is the database driver. Supported drivers are sqlite, postgres.
Driver string
// Version is the current version of server.
Version string
// Metric indicate the metric collection is enabled or not.
Metric bool
// Pubic is the flag whether the instance is public for others.
Public bool
// InstanceURL is the URL of the instance.
InstanceURL string
}
func (p *Profile) IsDev() bool {
@ -57,47 +57,36 @@ func checkDataDir(dataDir string) (string, error) {
return dataDir, nil
}
// GetProfile will return a profile for dev or prod.
func GetProfile() (*Profile, error) {
profile := Profile{}
err := viper.Unmarshal(&profile)
if err != nil {
return nil, err
func (p *Profile) Validate() error {
if p.Mode != "demo" && p.Mode != "dev" && p.Mode != "prod" {
p.Mode = "demo"
}
if profile.Mode != "demo" && profile.Mode != "dev" && profile.Mode != "prod" {
profile.Mode = "demo"
}
if profile.Mode == "prod" && profile.Data == "" {
if p.Mode == "prod" && p.Data == "" {
if runtime.GOOS == "windows" {
profile.Data = filepath.Join(os.Getenv("ProgramData"), "slash")
if _, err := os.Stat(profile.Data); os.IsNotExist(err) {
if err := os.MkdirAll(profile.Data, 0770); err != nil {
fmt.Printf("Failed to create data directory: %s, err: %+v\n", profile.Data, err)
return nil, err
p.Data = filepath.Join(os.Getenv("ProgramData"), "slash")
if _, err := os.Stat(p.Data); os.IsNotExist(err) {
if err := os.MkdirAll(p.Data, 0770); err != nil {
fmt.Printf("Failed to create data directory: %s, err: %+v\n", p.Data, err)
return err
}
}
} else {
profile.Data = "/var/opt/slash"
p.Data = "/var/opt/slash"
}
}
if profile.Driver == "sqlite" {
dataDir, err := checkDataDir(profile.Data)
if err != nil {
fmt.Printf("Failed to check dsn: %s, err: %+v\n", dataDir, err)
return nil, err
}
profile.Data = dataDir
if profile.DSN == "" {
dbFile := fmt.Sprintf("slash_%s.db", profile.Mode)
profile.DSN = filepath.Join(dataDir, dbFile)
}
dataDir, err := checkDataDir(p.Data)
if err != nil {
fmt.Printf("Failed to check dsn: %s, err: %+v\n", dataDir, err)
return err
}
profile.Version = version.GetCurrentVersion(profile.Mode)
return &profile, nil
p.Data = dataDir
if p.Driver == "sqlite" && p.DSN == "" {
dbFile := fmt.Sprintf("slash_%s.db", p.Mode)
p.DSN = filepath.Join(dataDir, dbFile)
}
return nil
}

View File

@ -163,7 +163,7 @@ func audienceContains(audience jwt.ClaimStrings, token string) bool {
return false
}
func validateAccessToken(accessTokenString string, userAccessTokens []*storepb.UserSettingAccessTokens_AccessToken) bool {
func validateAccessToken(accessTokenString string, userAccessTokens []*storepb.UserSetting_AccessTokensSetting_AccessToken) bool {
for _, userAccessToken := range userAccessTokens {
if accessTokenString == userAccessToken.AccessToken {
return true

View File

@ -12,7 +12,6 @@ import (
"google.golang.org/grpc/status"
v1pb "github.com/yourselfhosted/slash/proto/gen/api/v1"
storepb "github.com/yourselfhosted/slash/proto/gen/store"
"github.com/yourselfhosted/slash/server/metric"
"github.com/yourselfhosted/slash/server/service/license"
"github.com/yourselfhosted/slash/store"
@ -70,13 +69,7 @@ func (s *APIV1Service) SignIn(ctx context.Context, request *v1pb.SignInRequest)
}
func (s *APIV1Service) SignUp(ctx context.Context, request *v1pb.SignUpRequest) (*v1pb.SignUpResponse, error) {
enableSignUpSetting, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSAPCE_SETTING_ENABLE_SIGNUP,
})
if err != nil {
return nil, status.Errorf(codes.Internal, fmt.Sprintf("failed to get workspace setting, err: %s", err))
}
if enableSignUpSetting != nil && !enableSignUpSetting.GetEnableSignup() {
if !s.Profile.Public {
return nil, status.Errorf(codes.PermissionDenied, "sign up is not allowed")
}

View File

@ -251,7 +251,7 @@ func (s *APIV1Service) DeleteUserAccessToken(ctx context.Context, request *v1pb.
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to list access tokens: %v", err)
}
updatedUserAccessTokens := []*storepb.UserSettingAccessTokens_AccessToken{}
updatedUserAccessTokens := []*storepb.UserSetting_AccessTokensSetting_AccessToken{}
for _, userAccessToken := range userAccessTokens {
if userAccessToken.AccessToken == request.AccessToken {
continue
@ -260,9 +260,9 @@ func (s *APIV1Service) DeleteUserAccessToken(ctx context.Context, request *v1pb.
}
if _, err := s.Store.UpsertUserSetting(ctx, &storepb.UserSetting{
UserId: user.ID,
Key: storepb.UserSettingKey_ACCESS_TOKENS,
Key: storepb.UserSettingKey_USER_SETTING_ACCESS_TOKENS,
Value: &storepb.UserSetting_AccessTokens{
AccessTokens: &storepb.UserSettingAccessTokens{
AccessTokens: &storepb.UserSetting_AccessTokensSetting{
AccessTokens: updatedUserAccessTokens,
},
},
@ -278,16 +278,16 @@ func (s *APIV1Service) UpsertAccessTokenToStore(ctx context.Context, user *store
if err != nil {
return errors.Wrap(err, "failed to get user access tokens")
}
userAccessToken := storepb.UserSettingAccessTokens_AccessToken{
userAccessToken := storepb.UserSetting_AccessTokensSetting_AccessToken{
AccessToken: accessToken,
Description: description,
}
userAccessTokens = append(userAccessTokens, &userAccessToken)
if _, err := s.Store.UpsertUserSetting(ctx, &storepb.UserSetting{
UserId: user.ID,
Key: storepb.UserSettingKey_ACCESS_TOKENS,
Key: storepb.UserSettingKey_USER_SETTING_ACCESS_TOKENS,
Value: &storepb.UserSetting_AccessTokens{
AccessTokens: &storepb.UserSettingAccessTokens{
AccessTokens: &storepb.UserSetting_AccessTokensSetting{
AccessTokens: userAccessTokens,
},
},

View File

@ -35,9 +35,9 @@ func (s *APIV1Service) UpdateUserSetting(ctx context.Context, request *v1pb.Upda
if path == "general" {
if _, err := s.Store.UpsertUserSetting(ctx, &storepb.UserSetting{
UserId: user.ID,
Key: storepb.UserSettingKey_GENERAL,
Key: storepb.UserSettingKey_USER_SETTING_GENERAL,
Value: &storepb.UserSetting_General{
General: &storepb.UserSettingGeneral{
General: &storepb.UserSetting_GeneralSetting{
Locale: request.UserSetting.General.Locale,
ColorTheme: request.UserSetting.General.ColorTheme,
},
@ -68,15 +68,15 @@ func getUserSetting(ctx context.Context, s *store.Store, userID int32) (*v1pb.Us
}
userSetting := &v1pb.UserSetting{
Id: userID,
General: &v1pb.UserSettingGeneral{
UserId: userID,
General: &v1pb.UserSetting_GeneralSetting{
Locale: "EN",
ColorTheme: "SYSTEM",
},
}
for _, setting := range userSettings {
if setting.Key == storepb.UserSettingKey_GENERAL {
userSetting.General = &v1pb.UserSettingGeneral{
if setting.Key == storepb.UserSettingKey_USER_SETTING_GENERAL {
userSetting.General = &v1pb.UserSetting_GeneralSetting{
Locale: setting.GetGeneral().Locale,
ColorTheme: setting.GetGeneral().ColorTheme,
}

View File

@ -14,10 +14,11 @@ import (
)
func (s *APIV1Service) GetWorkspaceProfile(ctx context.Context, _ *v1pb.GetWorkspaceProfileRequest) (*v1pb.GetWorkspaceProfileResponse, error) {
profile := &v1pb.WorkspaceProfile{
Mode: s.Profile.Mode,
Version: s.Profile.Version,
Plan: v1pb.PlanType_FREE,
workspaceProfile := &v1pb.WorkspaceProfile{
Mode: s.Profile.Mode,
Version: s.Profile.Version,
Plan: v1pb.PlanType_FREE,
EnableSignup: s.Profile.Public,
}
// Load subscription plan from license service.
@ -25,66 +26,34 @@ func (s *APIV1Service) GetWorkspaceProfile(ctx context.Context, _ *v1pb.GetWorks
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get subscription: %v", err)
}
profile.Plan = subscription.Plan
workspaceProfile.Plan = subscription.Plan
workspaceSetting, err := s.GetWorkspaceSetting(ctx, &v1pb.GetWorkspaceSettingRequest{})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get workspace setting: %v", err)
}
if workspaceSetting != nil {
setting := workspaceSetting.GetSetting()
profile.EnableSignup = setting.GetEnableSignup()
profile.CustomStyle = setting.GetCustomStyle()
profile.FaviconProvider = setting.GetFaviconProvider()
}
owner, err := s.GetInstanceOwner(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get instance owner: %v", err)
}
if owner != nil {
profile.Owner = fmt.Sprintf("%s%d", UserNamePrefix, owner.Id)
workspaceProfile.Owner = fmt.Sprintf("%s%d", UserNamePrefix, owner.Id)
}
return &v1pb.GetWorkspaceProfileResponse{
Profile: profile,
Profile: workspaceProfile,
}, nil
}
func (s *APIV1Service) GetWorkspaceSetting(ctx context.Context, _ *v1pb.GetWorkspaceSettingRequest) (*v1pb.GetWorkspaceSettingResponse, error) {
isAdmin := false
userID, ok := ctx.Value(userIDContextKey).(int32)
if ok {
user, err := s.Store.GetUser(ctx, &store.FindUser{ID: &userID})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get user: %v", err)
}
if user.Role == store.RoleAdmin {
isAdmin = true
}
}
workspaceSettings, err := s.Store.ListWorkspaceSettings(ctx, &store.FindWorkspaceSetting{})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to list workspace settings: %v", err)
}
workspaceSetting := &v1pb.WorkspaceSetting{
EnableSignup: true,
}
workspaceSetting := &v1pb.WorkspaceSetting{}
for _, v := range workspaceSettings {
if v.Key == storepb.WorkspaceSettingKey_WORKSAPCE_SETTING_ENABLE_SIGNUP {
workspaceSetting.EnableSignup = v.GetEnableSignup()
} else if v.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_INSTANCE_URL {
workspaceSetting.InstanceUrl = v.GetInstanceUrl()
} else if v.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_CUSTOM_STYLE {
workspaceSetting.CustomStyle = v.GetCustomStyle()
} else if v.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_DEFAULT_VISIBILITY {
workspaceSetting.DefaultVisibility = v1pb.Visibility(v.GetDefaultVisibility())
} else if v.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_FAVICON_PROVIDER {
workspaceSetting.FaviconProvider = v.GetFaviconProvider()
} else if isAdmin {
// For some settings, only admin can get the value.
if v.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_LICENSE_KEY {
workspaceSetting.LicenseKey = v.GetLicenseKey()
}
if v.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_GENERAL {
generalSetting := v.GetGeneral()
workspaceSetting.CustomStyle = generalSetting.GetCustomStyle()
} else if v.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_SHORTCUT_RELATED {
shortcutRelatedSetting := v.GetShortcutRelated()
workspaceSetting.DefaultVisibility = v1pb.Visibility(shortcutRelatedSetting.GetDefaultVisibility())
}
}
return &v1pb.GetWorkspaceSettingResponse{
@ -98,56 +67,50 @@ func (s *APIV1Service) UpdateWorkspaceSetting(ctx context.Context, request *v1pb
}
for _, path := range request.UpdateMask.Paths {
if path == "license_key" {
if _, err := s.Store.UpsertWorkspaceSetting(ctx, &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_LICENSE_KEY,
Value: &storepb.WorkspaceSetting_LicenseKey{
LicenseKey: request.Setting.LicenseKey,
},
}); err != nil {
return nil, status.Errorf(codes.Internal, "failed to update workspace setting: %v", err)
if path == "custom_style" {
generalSetting, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_GENERAL,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get workspace setting: %v", err)
}
} else if path == "enable_signup" {
if _, err := s.Store.UpsertWorkspaceSetting(ctx, &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSAPCE_SETTING_ENABLE_SIGNUP,
Value: &storepb.WorkspaceSetting_EnableSignup{
EnableSignup: request.Setting.EnableSignup,
},
}); err != nil {
return nil, status.Errorf(codes.Internal, "failed to update workspace setting: %v", err)
if generalSetting == nil {
generalSetting = &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_GENERAL,
Value: &storepb.WorkspaceSetting_General{
General: &storepb.WorkspaceSetting_GeneralSetting{},
},
}
}
} else if path == "instance_url" {
generalSetting.GetGeneral().CustomStyle = request.Setting.CustomStyle
if _, err := s.Store.UpsertWorkspaceSetting(ctx, &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_INSTANCE_URL,
Value: &storepb.WorkspaceSetting_InstanceUrl{
InstanceUrl: request.Setting.InstanceUrl,
},
}); err != nil {
return nil, status.Errorf(codes.Internal, "failed to update workspace setting: %v", err)
}
} else if path == "custom_style" {
if _, err := s.Store.UpsertWorkspaceSetting(ctx, &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_CUSTOM_STYLE,
Value: &storepb.WorkspaceSetting_CustomStyle{
CustomStyle: request.Setting.CustomStyle,
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_GENERAL,
Value: &storepb.WorkspaceSetting_General{
General: generalSetting.GetGeneral(),
},
}); err != nil {
return nil, status.Errorf(codes.Internal, "failed to update workspace setting: %v", err)
}
} else if path == "default_visibility" {
if _, err := s.Store.UpsertWorkspaceSetting(ctx, &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_DEFAULT_VISIBILITY,
Value: &storepb.WorkspaceSetting_DefaultVisibility{
DefaultVisibility: storepb.Visibility(request.Setting.DefaultVisibility),
},
}); err != nil {
return nil, status.Errorf(codes.Internal, "failed to update workspace setting: %v", err)
shortcutRelatedSetting, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_SHORTCUT_RELATED,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get workspace setting: %v", err)
}
} else if path == "favicon_provider" {
if shortcutRelatedSetting == nil {
shortcutRelatedSetting = &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_SHORTCUT_RELATED,
Value: &storepb.WorkspaceSetting_ShortcutRelated{
ShortcutRelated: &storepb.WorkspaceSetting_ShortcutRelatedSetting{},
},
}
}
shortcutRelatedSetting.GetShortcutRelated().DefaultVisibility = storepb.Visibility(request.Setting.DefaultVisibility)
if _, err := s.Store.UpsertWorkspaceSetting(ctx, &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_FAVICON_PROVIDER,
Value: &storepb.WorkspaceSetting_FaviconProvider{
FaviconProvider: request.Setting.FaviconProvider,
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_SHORTCUT_RELATED,
Value: &storepb.WorkspaceSetting_ShortcutRelated{
ShortcutRelated: shortcutRelatedSetting.GetShortcutRelated(),
},
}); err != nil {
return nil, status.Errorf(codes.Internal, "failed to update workspace setting: %v", err)

View File

@ -118,13 +118,7 @@ func (s *FrontendService) registerRoutes(e *echo.Echo) {
}
func (s *FrontendService) registerFileRoutes(ctx context.Context, e *echo.Echo) {
instanceURLSetting, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_INSTANCE_URL,
})
if err != nil || instanceURLSetting == nil {
return
}
instanceURL := instanceURLSetting.GetInstanceUrl()
instanceURL := s.Profile.InstanceURL
if instanceURL == "" {
return
}

View File

@ -120,23 +120,25 @@ func (s *Server) GetEcho() *echo.Echo {
}
func (s *Server) getSecretSessionName(ctx context.Context) (string, error) {
secretSessionSetting, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_SECRET_SESSION,
workspaceSettingGeneral, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_GENERAL,
})
if err != nil {
return "", err
}
if secretSessionSetting == nil {
if workspaceSettingGeneral == nil || workspaceSettingGeneral.GetGeneral() == nil {
tempSecret := uuid.New().String()
secretSessionSetting, err = s.Store.UpsertWorkspaceSetting(ctx, &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_SECRET_SESSION,
Value: &storepb.WorkspaceSetting_SecretSession{
SecretSession: tempSecret,
workspaceSettingGeneral, err = s.Store.UpsertWorkspaceSetting(ctx, &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_GENERAL,
Value: &storepb.WorkspaceSetting_General{
General: &storepb.WorkspaceSetting_GeneralSetting{
SecretSession: tempSecret,
},
},
})
if err != nil {
return "", err
}
}
return secretSessionSetting.GetSecretSession(), nil
return workspaceSettingGeneral.GetGeneral().SecretSession, nil
}

View File

@ -38,8 +38,8 @@ func NewLicenseService(profile *profile.Profile, store *store.Store) *LicenseSer
}
func (s *LicenseService) LoadSubscription(ctx context.Context) (*v1pb.Subscription, error) {
workspaceSetting, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_LICENSE_KEY,
workspaceSettingGeneral, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_GENERAL,
})
if err != nil {
return nil, errors.Wrap(err, "failed to get workspace setting")
@ -48,8 +48,8 @@ func (s *LicenseService) LoadSubscription(ctx context.Context) (*v1pb.Subscripti
Plan: v1pb.PlanType_FREE,
}
licenseKey := ""
if workspaceSetting != nil {
licenseKey = workspaceSetting.GetLicenseKey()
if workspaceSettingGeneral != nil {
licenseKey = workspaceSettingGeneral.GetGeneral().LicenseKey
}
if licenseKey == "" {
return subscription, nil
@ -79,12 +79,25 @@ func (s *LicenseService) UpdateSubscription(ctx context.Context, licenseKey stri
if result == nil {
return nil, errors.New("invalid license key")
}
_, err = s.Store.UpsertWorkspaceSetting(ctx, &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_LICENSE_KEY,
Value: &storepb.WorkspaceSetting_LicenseKey{
LicenseKey: licenseKey,
},
workspaceSettingGeneral, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_GENERAL,
})
if err != nil {
return nil, errors.Wrap(err, "failed to get workspace setting")
}
if workspaceSettingGeneral == nil || workspaceSettingGeneral.GetGeneral() == nil {
workspaceSettingGeneral = &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_GENERAL,
Value: &storepb.WorkspaceSetting_General{
General: &storepb.WorkspaceSetting_GeneralSetting{
LicenseKey: licenseKey,
},
},
}
} else {
workspaceSettingGeneral.GetGeneral().LicenseKey = licenseKey
}
_, err = s.Store.UpsertWorkspaceSetting(ctx, workspaceSettingGeneral)
if err != nil {
return nil, errors.Wrap(err, "failed to upsert workspace setting")
}