Unverified Commit 9ef0f8a9 authored by boojack's avatar boojack Committed by GitHub

feat: add user setting field (#2054)

parent 470fe1df
...@@ -23,7 +23,6 @@ func NewUserService(store *store.Store) *UserService { ...@@ -23,7 +23,6 @@ func NewUserService(store *store.Store) *UserService {
} }
func (s *UserService) GetUser(ctx context.Context, request *apiv2pb.GetUserRequest) (*apiv2pb.GetUserResponse, error) { func (s *UserService) GetUser(ctx context.Context, request *apiv2pb.GetUserRequest) (*apiv2pb.GetUserResponse, error) {
println("GetUser", request.Name)
user, err := s.Store.GetUser(ctx, &store.FindUser{ user, err := s.Store.GetUser(ctx, &store.FindUser{
Username: &request.Name, Username: &request.Name,
}) })
...@@ -38,6 +37,18 @@ func (s *UserService) GetUser(ctx context.Context, request *apiv2pb.GetUserReque ...@@ -38,6 +37,18 @@ func (s *UserService) GetUser(ctx context.Context, request *apiv2pb.GetUserReque
// Data desensitization. // Data desensitization.
userMessage.OpenId = "" userMessage.OpenId = ""
userUID := int(userMessage.Id)
userSettings, err := s.Store.ListUserSettings(ctx, &store.FindUserSetting{
UserID: &userUID,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to list user settings: %v", err)
}
// TODO: check the access permission for user settings.
for _, userSetting := range userSettings {
userMessage.Settings = append(userMessage.Settings, convertUserSettingFromStore(userSetting))
}
response := &apiv2pb.GetUserResponse{ response := &apiv2pb.GetUserResponse{
User: userMessage, User: userMessage,
} }
...@@ -56,6 +67,7 @@ func convertUserFromStore(user *store.User) *apiv2pb.User { ...@@ -56,6 +67,7 @@ func convertUserFromStore(user *store.User) *apiv2pb.User {
Nickname: user.Nickname, Nickname: user.Nickname,
OpenId: user.OpenID, OpenId: user.OpenID,
AvatarUrl: user.AvatarURL, AvatarUrl: user.AvatarURL,
Settings: []*apiv2pb.UserSetting{},
} }
} }
...@@ -71,3 +83,46 @@ func convertUserRoleFromStore(role store.Role) apiv2pb.Role { ...@@ -71,3 +83,46 @@ func convertUserRoleFromStore(role store.Role) apiv2pb.Role {
return apiv2pb.Role_ROLE_UNSPECIFIED return apiv2pb.Role_ROLE_UNSPECIFIED
} }
} }
func convertUserSettingFromStore(userSetting *store.UserSetting) *apiv2pb.UserSetting {
userSettingKey := apiv2pb.UserSetting_KEY_UNSPECIFIED
userSettingValue := &apiv2pb.UserSettingValue{}
switch userSetting.Key {
case "locale":
userSettingKey = apiv2pb.UserSetting_LOCALE
userSettingValue.Value = &apiv2pb.UserSettingValue_StringValue{
StringValue: userSetting.Value,
}
case "appearance":
userSettingKey = apiv2pb.UserSetting_APPEARANCE
userSettingValue.Value = &apiv2pb.UserSettingValue_StringValue{
StringValue: userSetting.Value,
}
case "memo-visibility":
userSettingKey = apiv2pb.UserSetting_MEMO_VISIBILITY
userSettingValue.Value = &apiv2pb.UserSettingValue_VisibilityValue{
VisibilityValue: convertVisibilityFromString(userSetting.Value),
}
case "telegram-user-id":
userSettingKey = apiv2pb.UserSetting_TELEGRAM_USER_ID
userSettingValue.Value = &apiv2pb.UserSettingValue_StringValue{
StringValue: userSetting.Value,
}
}
return &apiv2pb.UserSetting{
UserId: int32(userSetting.UserID),
Key: userSettingKey,
Value: userSettingValue,
}
}
func convertVisibilityFromString(visibility string) apiv2pb.Visibility {
switch visibility {
case "public":
return apiv2pb.Visibility_PUBLIC
case "private":
return apiv2pb.Visibility_PRIVATE
default:
return apiv2pb.Visibility_VISIBILITY_UNSPECIFIED
}
}
...@@ -35,6 +35,8 @@ message User { ...@@ -35,6 +35,8 @@ message User {
string open_id = 9; string open_id = 9;
string avatar_url = 10; string avatar_url = 10;
repeated UserSetting settings = 11;
} }
enum Role { enum Role {
...@@ -54,3 +56,43 @@ message GetUserRequest { ...@@ -54,3 +56,43 @@ message GetUserRequest {
message GetUserResponse { message GetUserResponse {
User user = 1; User user = 1;
} }
message UserSetting {
// The user id of the setting.
int32 user_id = 1;
enum Key {
KEY_UNSPECIFIED = 0;
// The preferred locale.
LOCALE = 1;
// The preferred appearance.
APPEARANCE = 2;
// The default visibility of the memo when creating a new memo.
MEMO_VISIBILITY = 3;
// User's telegram id
TELEGRAM_USER_ID = 4;
}
// The key of the setting.
Key key = 2;
// The value of the setting.
UserSettingValue value = 3;
}
message UserSettingValue {
oneof value {
// Default value as a string.
string string_value = 1;
Visibility visibility_value = 2;
}
}
enum Visibility {
VISIBILITY_UNSPECIFIED = 0;
PRIVATE = 1;
PROTECTED = 2;
PUBLIC = 3;
}
...@@ -17,8 +17,12 @@ ...@@ -17,8 +17,12 @@
- [GetUserRequest](#memos-api-v2-GetUserRequest) - [GetUserRequest](#memos-api-v2-GetUserRequest)
- [GetUserResponse](#memos-api-v2-GetUserResponse) - [GetUserResponse](#memos-api-v2-GetUserResponse)
- [User](#memos-api-v2-User) - [User](#memos-api-v2-User)
- [UserSetting](#memos-api-v2-UserSetting)
- [UserSettingValue](#memos-api-v2-UserSettingValue)
- [Role](#memos-api-v2-Role) - [Role](#memos-api-v2-Role)
- [UserSetting.Key](#memos-api-v2-UserSetting-Key)
- [Visibility](#memos-api-v2-Visibility)
- [UserService](#memos-api-v2-UserService) - [UserService](#memos-api-v2-UserService)
...@@ -182,6 +186,40 @@ ...@@ -182,6 +186,40 @@
| nickname | [string](#string) | | | | nickname | [string](#string) | | |
| open_id | [string](#string) | | | | open_id | [string](#string) | | |
| avatar_url | [string](#string) | | | | avatar_url | [string](#string) | | |
| settings | [UserSetting](#memos-api-v2-UserSetting) | repeated | |
<a name="memos-api-v2-UserSetting"></a>
### UserSetting
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| user_id | [int32](#int32) | | The user id of the setting. |
| key | [UserSetting.Key](#memos-api-v2-UserSetting-Key) | | The key of the setting. |
| value | [UserSettingValue](#memos-api-v2-UserSettingValue) | | The value of the setting. |
<a name="memos-api-v2-UserSettingValue"></a>
### UserSettingValue
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| string_value | [string](#string) | | Default value as a string. |
| visibility_value | [Visibility](#memos-api-v2-Visibility) | | |
...@@ -203,6 +241,35 @@ ...@@ -203,6 +241,35 @@
| USER | 3 | | | USER | 3 | |
<a name="memos-api-v2-UserSetting-Key"></a>
### UserSetting.Key
| Name | Number | Description |
| ---- | ------ | ----------- |
| KEY_UNSPECIFIED | 0 | |
| LOCALE | 1 | The preferred locale. |
| APPEARANCE | 2 | The preferred appearance. |
| MEMO_VISIBILITY | 3 | The default visibility of the memo when creating a new memo. |
| TELEGRAM_USER_ID | 4 | User&#39;s telegram id |
<a name="memos-api-v2-Visibility"></a>
### Visibility
| Name | Number | Description |
| ---- | ------ | ----------- |
| VISIBILITY_UNSPECIFIED | 0 | |
| PRIVATE | 1 | |
| PROTECTED | 2 | |
| PUBLIC | 3 | |
......
This diff is collapsed.
...@@ -12,8 +12,18 @@ import ( ...@@ -12,8 +12,18 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
) )
func autoBackup(ctx context.Context, s *store.Store) { type BackupRunner struct {
intervalStr := s.GetSystemSettingValueWithDefault(&ctx, apiv1.SystemSettingAutoBackupIntervalName.String(), "") Store *store.Store
}
func NewBackupRunner(store *store.Store) *BackupRunner {
return &BackupRunner{
Store: store,
}
}
func (r *BackupRunner) Run(ctx context.Context) {
intervalStr := r.Store.GetSystemSettingValueWithDefault(&ctx, apiv1.SystemSettingAutoBackupIntervalName.String(), "")
if intervalStr == "" { if intervalStr == "" {
log.Info("no SystemSettingAutoBackupIntervalName setting, disable auto backup") log.Info("no SystemSettingAutoBackupIntervalName setting, disable auto backup")
return return
...@@ -38,9 +48,9 @@ func autoBackup(ctx context.Context, s *store.Store) { ...@@ -38,9 +48,9 @@ func autoBackup(ctx context.Context, s *store.Store) {
case t = <-ticker.C: case t = <-ticker.C:
} }
filename := s.Profile.DSN + t.Format("-20060102-150405.bak") filename := r.Store.Profile.DSN + t.Format("-20060102-150405.bak")
log.Info(fmt.Sprintf("create backup to %s", filename)) log.Info(fmt.Sprintf("create backup to %s", filename))
err := s.BackupTo(ctx, filename) err := r.Store.BackupTo(ctx, filename)
if err != nil { if err != nil {
log.Error("fail to create backup", zap.Error(err)) log.Error("fail to create backup", zap.Error(err))
} }
......
...@@ -32,7 +32,9 @@ type Server struct { ...@@ -32,7 +32,9 @@ type Server struct {
Profile *profile.Profile Profile *profile.Profile
Store *store.Store Store *store.Store
telegramBot *telegram.Bot // Asynchronous runners.
backupRunner *BackupRunner
telegramBot *telegram.Bot
} }
func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store) (*Server, error) { func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store) (*Server, error) {
...@@ -45,10 +47,11 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store ...@@ -45,10 +47,11 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store
e: e, e: e,
Store: store, Store: store,
Profile: profile, Profile: profile,
}
telegramBotHandler := newTelegramHandler(store) // Asynchronous runners.
s.telegramBot = telegram.NewBotWithHandler(telegramBotHandler) backupRunner: NewBackupRunner(store),
telegramBot: telegram.NewBotWithHandler(newTelegramHandler(store)),
}
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{ e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
Format: `{"time":"${time_rfc3339}",` + Format: `{"time":"${time_rfc3339}",` +
...@@ -116,7 +119,7 @@ func (s *Server) Start(ctx context.Context) error { ...@@ -116,7 +119,7 @@ func (s *Server) Start(ctx context.Context) error {
} }
go s.telegramBot.Start(ctx) go s.telegramBot.Start(ctx)
go autoBackup(ctx, s.Store) go s.backupRunner.Run(ctx)
// Start gRPC server. // Start gRPC server.
listen, err := net.Listen("tcp", fmt.Sprintf(":%d", s.Profile.Port+1)) listen, err := net.Listen("tcp", fmt.Sprintf(":%d", s.Profile.Port+1))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment