From fb3267d1394c05a407be3eb49ee5e6c5702faf18 Mon Sep 17 00:00:00 2001 From: Steven Date: Sun, 6 Aug 2023 13:46:52 +0800 Subject: [PATCH] feat: add access tokens to user setting --- proto/gen/store/README.md | 86 ++++++ proto/gen/store/user_setting.pb.go | 438 +++++++++++++++++++++++++++++ proto/store/user_setting.proto | 34 +++ store/user_setting.go | 72 +++-- test/store/user_setting_test.go | 73 +++++ 5 files changed, 677 insertions(+), 26 deletions(-) create mode 100644 proto/gen/store/user_setting.pb.go create mode 100644 proto/store/user_setting.proto create mode 100644 test/store/user_setting_test.go diff --git a/proto/gen/store/README.md b/proto/gen/store/README.md index 348a862f..aa40e768 100644 --- a/proto/gen/store/README.md +++ b/proto/gen/store/README.md @@ -12,6 +12,13 @@ - [Visibility](#slash-store-Visibility) +- [store/user_setting.proto](#store_user_setting-proto) + - [AccessTokensUserSetting](#slash-store-AccessTokensUserSetting) + - [AccessTokensUserSetting.AccessToken](#slash-store-AccessTokensUserSetting-AccessToken) + - [UserSetting](#slash-store-UserSetting) + + - [UserSettingKey](#slash-store-UserSettingKey) + - [Scalar Value Types](#scalar-value-types) @@ -118,6 +125,85 @@ + +

Top

+ +## store/user_setting.proto + + + + + +### AccessTokensUserSetting + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| access_tokens | [AccessTokensUserSetting.AccessToken](#slash-store-AccessTokensUserSetting-AccessToken) | repeated | | + + + + + + + + +### AccessTokensUserSetting.AccessToken + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| access_token | [string](#string) | | | +| description | [string](#string) | | | +| created_time | [google.protobuf.Timestamp](#google-protobuf-Timestamp) | | | +| expires_time | [google.protobuf.Timestamp](#google-protobuf-Timestamp) | | | +| revoked | [bool](#bool) | | | + + + + + + + + +### UserSetting + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| user_id | [int32](#int32) | | | +| key | [UserSettingKey](#slash-store-UserSettingKey) | | | +| access_tokens_user_setting | [AccessTokensUserSetting](#slash-store-AccessTokensUserSetting) | | | + + + + + + + + + + +### UserSettingKey + + +| Name | Number | Description | +| ---- | ------ | ----------- | +| USER_SETTING_KEY_UNSPECIFIED | 0 | | +| USER_SETTING_ACCESS_TOKENS | 1 | | + + + + + + + + + + ## Scalar Value Types | .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby | diff --git a/proto/gen/store/user_setting.pb.go b/proto/gen/store/user_setting.pb.go new file mode 100644 index 00000000..12f16f0d --- /dev/null +++ b/proto/gen/store/user_setting.pb.go @@ -0,0 +1,438 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: store/user_setting.proto + +package store + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type UserSettingKey int32 + +const ( + UserSettingKey_USER_SETTING_KEY_UNSPECIFIED UserSettingKey = 0 + UserSettingKey_USER_SETTING_ACCESS_TOKENS UserSettingKey = 1 +) + +// Enum value maps for UserSettingKey. +var ( + UserSettingKey_name = map[int32]string{ + 0: "USER_SETTING_KEY_UNSPECIFIED", + 1: "USER_SETTING_ACCESS_TOKENS", + } + UserSettingKey_value = map[string]int32{ + "USER_SETTING_KEY_UNSPECIFIED": 0, + "USER_SETTING_ACCESS_TOKENS": 1, + } +) + +func (x UserSettingKey) Enum() *UserSettingKey { + p := new(UserSettingKey) + *p = x + return p +} + +func (x UserSettingKey) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (UserSettingKey) Descriptor() protoreflect.EnumDescriptor { + return file_store_user_setting_proto_enumTypes[0].Descriptor() +} + +func (UserSettingKey) Type() protoreflect.EnumType { + return &file_store_user_setting_proto_enumTypes[0] +} + +func (x UserSettingKey) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use UserSettingKey.Descriptor instead. +func (UserSettingKey) EnumDescriptor() ([]byte, []int) { + return file_store_user_setting_proto_rawDescGZIP(), []int{0} +} + +type UserSetting struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId int32 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + Key UserSettingKey `protobuf:"varint,2,opt,name=key,proto3,enum=slash.store.UserSettingKey" json:"key,omitempty"` + // Types that are assignable to Value: + // + // *UserSetting_AccessTokensUserSetting + Value isUserSetting_Value `protobuf_oneof:"value"` +} + +func (x *UserSetting) Reset() { + *x = UserSetting{} + if protoimpl.UnsafeEnabled { + mi := &file_store_user_setting_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserSetting) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserSetting) ProtoMessage() {} + +func (x *UserSetting) ProtoReflect() protoreflect.Message { + mi := &file_store_user_setting_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserSetting.ProtoReflect.Descriptor instead. +func (*UserSetting) Descriptor() ([]byte, []int) { + return file_store_user_setting_proto_rawDescGZIP(), []int{0} +} + +func (x *UserSetting) GetUserId() int32 { + if x != nil { + return x.UserId + } + return 0 +} + +func (x *UserSetting) GetKey() UserSettingKey { + if x != nil { + return x.Key + } + return UserSettingKey_USER_SETTING_KEY_UNSPECIFIED +} + +func (m *UserSetting) GetValue() isUserSetting_Value { + if m != nil { + return m.Value + } + return nil +} + +func (x *UserSetting) GetAccessTokensUserSetting() *AccessTokensUserSetting { + if x, ok := x.GetValue().(*UserSetting_AccessTokensUserSetting); ok { + return x.AccessTokensUserSetting + } + return nil +} + +type isUserSetting_Value interface { + isUserSetting_Value() +} + +type UserSetting_AccessTokensUserSetting struct { + AccessTokensUserSetting *AccessTokensUserSetting `protobuf:"bytes,3,opt,name=access_tokens_user_setting,json=accessTokensUserSetting,proto3,oneof"` +} + +func (*UserSetting_AccessTokensUserSetting) isUserSetting_Value() {} + +type AccessTokensUserSetting struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AccessTokens []*AccessTokensUserSetting_AccessToken `protobuf:"bytes,1,rep,name=access_tokens,json=accessTokens,proto3" json:"access_tokens,omitempty"` +} + +func (x *AccessTokensUserSetting) Reset() { + *x = AccessTokensUserSetting{} + if protoimpl.UnsafeEnabled { + mi := &file_store_user_setting_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AccessTokensUserSetting) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AccessTokensUserSetting) ProtoMessage() {} + +func (x *AccessTokensUserSetting) ProtoReflect() protoreflect.Message { + mi := &file_store_user_setting_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AccessTokensUserSetting.ProtoReflect.Descriptor instead. +func (*AccessTokensUserSetting) Descriptor() ([]byte, []int) { + return file_store_user_setting_proto_rawDescGZIP(), []int{1} +} + +func (x *AccessTokensUserSetting) GetAccessTokens() []*AccessTokensUserSetting_AccessToken { + if x != nil { + return x.AccessTokens + } + return nil +} + +type AccessTokensUserSetting_AccessToken struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AccessToken string `protobuf:"bytes,1,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + CreatedTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=created_time,json=createdTime,proto3" json:"created_time,omitempty"` + ExpiresTime *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=expires_time,json=expiresTime,proto3" json:"expires_time,omitempty"` + Revoked bool `protobuf:"varint,5,opt,name=revoked,proto3" json:"revoked,omitempty"` +} + +func (x *AccessTokensUserSetting_AccessToken) Reset() { + *x = AccessTokensUserSetting_AccessToken{} + if protoimpl.UnsafeEnabled { + mi := &file_store_user_setting_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AccessTokensUserSetting_AccessToken) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AccessTokensUserSetting_AccessToken) ProtoMessage() {} + +func (x *AccessTokensUserSetting_AccessToken) ProtoReflect() protoreflect.Message { + mi := &file_store_user_setting_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AccessTokensUserSetting_AccessToken.ProtoReflect.Descriptor instead. +func (*AccessTokensUserSetting_AccessToken) Descriptor() ([]byte, []int) { + return file_store_user_setting_proto_rawDescGZIP(), []int{1, 0} +} + +func (x *AccessTokensUserSetting_AccessToken) GetAccessToken() string { + if x != nil { + return x.AccessToken + } + return "" +} + +func (x *AccessTokensUserSetting_AccessToken) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *AccessTokensUserSetting_AccessToken) GetCreatedTime() *timestamppb.Timestamp { + if x != nil { + return x.CreatedTime + } + return nil +} + +func (x *AccessTokensUserSetting_AccessToken) GetExpiresTime() *timestamppb.Timestamp { + if x != nil { + return x.ExpiresTime + } + return nil +} + +func (x *AccessTokensUserSetting_AccessToken) GetRevoked() bool { + if x != nil { + return x.Revoked + } + return false +} + +var File_store_user_setting_proto protoreflect.FileDescriptor + +var file_store_user_setting_proto_rawDesc = []byte{ + 0x0a, 0x18, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x73, 0x6c, 0x61, 0x73, + 0x68, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc3, 0x01, 0x0a, 0x0b, 0x55, 0x73, 0x65, + 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, + 0x64, 0x12, 0x2d, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, + 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x55, 0x73, 0x65, + 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x63, 0x0a, 0x1a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x73, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x73, 0x74, 0x6f, + 0x72, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x55, + 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x17, 0x61, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xdd, + 0x02, 0x0a, 0x17, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x55, + 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x55, 0x0a, 0x0d, 0x61, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x30, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, + 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x55, 0x73, 0x65, 0x72, + 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x52, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x73, 0x1a, 0xea, 0x01, 0x0a, 0x0b, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3d, 0x0a, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x0c, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, + 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x2a, 0x52, + 0x0a, 0x0e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, + 0x12, 0x20, 0x0a, 0x1c, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, + 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, + 0x4e, 0x47, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x54, 0x4f, 0x4b, 0x45, 0x4e, 0x53, + 0x10, 0x01, 0x42, 0x9a, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, + 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x10, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, + 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x6f, 0x6f, 0x6a, 0x61, 0x63, 0x6b, 0x2f, 0x73, + 0x6c, 0x61, 0x73, 0x68, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0xa2, 0x02, 0x03, 0x53, 0x53, 0x58, 0xaa, 0x02, 0x0b, 0x53, 0x6c, 0x61, + 0x73, 0x68, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xca, 0x02, 0x0b, 0x53, 0x6c, 0x61, 0x73, 0x68, + 0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xe2, 0x02, 0x17, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x5c, 0x53, + 0x74, 0x6f, 0x72, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0xea, 0x02, 0x0c, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x3a, 0x3a, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_store_user_setting_proto_rawDescOnce sync.Once + file_store_user_setting_proto_rawDescData = file_store_user_setting_proto_rawDesc +) + +func file_store_user_setting_proto_rawDescGZIP() []byte { + file_store_user_setting_proto_rawDescOnce.Do(func() { + file_store_user_setting_proto_rawDescData = protoimpl.X.CompressGZIP(file_store_user_setting_proto_rawDescData) + }) + return file_store_user_setting_proto_rawDescData +} + +var file_store_user_setting_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_store_user_setting_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_store_user_setting_proto_goTypes = []interface{}{ + (UserSettingKey)(0), // 0: slash.store.UserSettingKey + (*UserSetting)(nil), // 1: slash.store.UserSetting + (*AccessTokensUserSetting)(nil), // 2: slash.store.AccessTokensUserSetting + (*AccessTokensUserSetting_AccessToken)(nil), // 3: slash.store.AccessTokensUserSetting.AccessToken + (*timestamppb.Timestamp)(nil), // 4: google.protobuf.Timestamp +} +var file_store_user_setting_proto_depIdxs = []int32{ + 0, // 0: slash.store.UserSetting.key:type_name -> slash.store.UserSettingKey + 2, // 1: slash.store.UserSetting.access_tokens_user_setting:type_name -> slash.store.AccessTokensUserSetting + 3, // 2: slash.store.AccessTokensUserSetting.access_tokens:type_name -> slash.store.AccessTokensUserSetting.AccessToken + 4, // 3: slash.store.AccessTokensUserSetting.AccessToken.created_time:type_name -> google.protobuf.Timestamp + 4, // 4: slash.store.AccessTokensUserSetting.AccessToken.expires_time:type_name -> google.protobuf.Timestamp + 5, // [5:5] is the sub-list for method output_type + 5, // [5:5] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name +} + +func init() { file_store_user_setting_proto_init() } +func file_store_user_setting_proto_init() { + if File_store_user_setting_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_store_user_setting_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserSetting); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_store_user_setting_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AccessTokensUserSetting); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_store_user_setting_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AccessTokensUserSetting_AccessToken); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_store_user_setting_proto_msgTypes[0].OneofWrappers = []interface{}{ + (*UserSetting_AccessTokensUserSetting)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_store_user_setting_proto_rawDesc, + NumEnums: 1, + NumMessages: 3, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_store_user_setting_proto_goTypes, + DependencyIndexes: file_store_user_setting_proto_depIdxs, + EnumInfos: file_store_user_setting_proto_enumTypes, + MessageInfos: file_store_user_setting_proto_msgTypes, + }.Build() + File_store_user_setting_proto = out.File + file_store_user_setting_proto_rawDesc = nil + file_store_user_setting_proto_goTypes = nil + file_store_user_setting_proto_depIdxs = nil +} diff --git a/proto/store/user_setting.proto b/proto/store/user_setting.proto new file mode 100644 index 00000000..a3e2d67f --- /dev/null +++ b/proto/store/user_setting.proto @@ -0,0 +1,34 @@ +syntax = "proto3"; + +package slash.store; + +import "google/protobuf/timestamp.proto"; + +option go_package = "gen/store"; + +message UserSetting { + int32 user_id = 1; + + UserSettingKey key = 2; + + oneof value { + AccessTokensUserSetting access_tokens_user_setting = 3; + } +} + +enum UserSettingKey { + USER_SETTING_KEY_UNSPECIFIED = 0; + + USER_SETTING_ACCESS_TOKENS = 1; +} + +message AccessTokensUserSetting { + message AccessToken { + string access_token = 1; + string description = 2; + google.protobuf.Timestamp created_time = 3; + google.protobuf.Timestamp expires_time = 4; + bool revoked = 5; + } + repeated AccessToken access_tokens = 1; +} diff --git a/store/user_setting.go b/store/user_setting.go index 4d1e72d0..3f921e92 100644 --- a/store/user_setting.go +++ b/store/user_setting.go @@ -3,21 +3,19 @@ package store import ( "context" "database/sql" + "errors" "strings" -) -type UserSetting struct { - UserID int32 - Key string - Value string -} + storepb "github.com/boojack/slash/proto/gen/store" + "google.golang.org/protobuf/encoding/protojson" +) type FindUserSetting struct { UserID *int32 - Key string + Key storepb.UserSettingKey } -func (s *Store) UpsertUserSetting(ctx context.Context, upsert *UserSetting) (*UserSetting, error) { +func (s *Store) UpsertUserSetting(ctx context.Context, upsert *storepb.UserSetting) (*storepb.UserSetting, error) { stmt := ` INSERT INTO user_setting ( user_id, key, value @@ -26,20 +24,31 @@ func (s *Store) UpsertUserSetting(ctx context.Context, upsert *UserSetting) (*Us ON CONFLICT(user_id, key) DO UPDATE SET value = EXCLUDED.value ` - if _, err := s.db.ExecContext(ctx, stmt, upsert.UserID, upsert.Key, upsert.Value); err != nil { + var valueString string + if upsert.Key == storepb.UserSettingKey_USER_SETTING_ACCESS_TOKENS { + valueBytes, err := protojson.Marshal(upsert.GetAccessTokensUserSetting()) + if err != nil { + return nil, err + } + valueString = string(valueBytes) + } else { + return nil, errors.New("invalid user setting key") + } + + if _, err := s.db.ExecContext(ctx, stmt, upsert.UserId, upsert.Key.String(), valueString); err != nil { return nil, err } userSettingMessage := upsert - s.userSettingCache.Store(getUserSettingCacheKey(userSettingMessage.UserID, userSettingMessage.Key), userSettingMessage) + s.userSettingCache.Store(getUserSettingCacheKey(userSettingMessage.UserId, userSettingMessage.Key.String()), userSettingMessage) return userSettingMessage, nil } -func (s *Store) ListUserSettings(ctx context.Context, find *FindUserSetting) ([]*UserSetting, error) { +func (s *Store) ListUserSettings(ctx context.Context, find *FindUserSetting) ([]*storepb.UserSetting, error) { where, args := []string{"1 = 1"}, []any{} - if v := find.Key; v != "" { - where, args = append(where, "key = ?"), append(args, v) + if v := find.Key; v != storepb.UserSettingKey_USER_SETTING_KEY_UNSPECIFIED { + where, args = append(where, "key = ?"), append(args, v.String()) } if v := find.UserID; v != nil { where, args = append(where, "user_id = ?"), append(args, *find.UserID) @@ -58,16 +67,27 @@ func (s *Store) ListUserSettings(ctx context.Context, find *FindUserSetting) ([] } defer rows.Close() - userSettingList := make([]*UserSetting, 0) + userSettingList := make([]*storepb.UserSetting, 0) for rows.Next() { - userSetting := &UserSetting{} + userSetting := &storepb.UserSetting{} + var keyString, valueString string if err := rows.Scan( - &userSetting.UserID, - &userSetting.Key, - &userSetting.Value, + &userSetting.UserId, + &keyString, + &valueString, ); err != nil { return nil, err } + userSetting.Key = storepb.UserSettingKey(storepb.UserSettingKey_value[keyString]) + if userSetting.Key == storepb.UserSettingKey_USER_SETTING_ACCESS_TOKENS { + accessTokensUserSetting := &storepb.AccessTokensUserSetting{} + if err := protojson.Unmarshal([]byte(valueString), accessTokensUserSetting); err != nil { + return nil, err + } + userSetting.Value = &storepb.UserSetting_AccessTokensUserSetting{ + AccessTokensUserSetting: accessTokensUserSetting, + } + } userSettingList = append(userSettingList, userSetting) } @@ -76,15 +96,15 @@ func (s *Store) ListUserSettings(ctx context.Context, find *FindUserSetting) ([] } for _, userSetting := range userSettingList { - s.userSettingCache.Store(getUserSettingCacheKey(userSetting.UserID, userSetting.Key), userSetting) + s.userSettingCache.Store(getUserSettingCacheKey(userSetting.UserId, userSetting.Key.String()), userSetting) } return userSettingList, nil } -func (s *Store) GetUserSetting(ctx context.Context, find *FindUserSetting) (*UserSetting, error) { - if find.UserID != nil && find.Key != "" { - if cache, ok := s.userSettingCache.Load(getUserSettingCacheKey(*find.UserID, find.Key)); ok { - return cache.(*UserSetting), nil +func (s *Store) GetUserSetting(ctx context.Context, find *FindUserSetting) (*storepb.UserSetting, error) { + if find.UserID != nil && find.Key != storepb.UserSettingKey_USER_SETTING_KEY_UNSPECIFIED { + if cache, ok := s.userSettingCache.Load(getUserSettingCacheKey(*find.UserID, find.Key.String())); ok { + return cache.(*storepb.UserSetting), nil } } @@ -97,9 +117,9 @@ func (s *Store) GetUserSetting(ctx context.Context, find *FindUserSetting) (*Use return nil, nil } - userSettingMessage := list[0] - s.userSettingCache.Store(getUserSettingCacheKey(userSettingMessage.UserID, userSettingMessage.Key), userSettingMessage) - return userSettingMessage, nil + userSetting := list[0] + s.userSettingCache.Store(getUserSettingCacheKey(userSetting.UserId, userSetting.Key.String()), userSetting) + return userSetting, nil } func vacuumUserSetting(ctx context.Context, tx *sql.Tx) error { diff --git a/test/store/user_setting_test.go b/test/store/user_setting_test.go new file mode 100644 index 00000000..654e635c --- /dev/null +++ b/test/store/user_setting_test.go @@ -0,0 +1,73 @@ +package teststore + +import ( + "context" + "testing" + + storepb "github.com/boojack/slash/proto/gen/store" + "github.com/boojack/slash/store" + "github.com/stretchr/testify/require" +) + +func TestUserSettingStore(t *testing.T) { + ctx := context.Background() + ts := NewTestingStore(ctx, t) + user, err := createTestingAdminUser(ctx, ts) + require.NoError(t, err) + userSettings, err := ts.ListUserSettings(ctx, &store.FindUserSetting{ + UserID: &user.ID, + }) + require.NoError(t, err) + require.Equal(t, 0, len(userSettings)) + accessTokensUserSetting, err := ts.UpsertUserSetting(ctx, &storepb.UserSetting{ + UserId: user.ID, + Key: storepb.UserSettingKey_USER_SETTING_ACCESS_TOKENS, + Value: &storepb.UserSetting_AccessTokensUserSetting{ + AccessTokensUserSetting: &storepb.AccessTokensUserSetting{ + AccessTokens: []*storepb.AccessTokensUserSetting_AccessToken{ + { + AccessToken: "test_access_token", + }, + }, + }, + }, + }) + require.NoError(t, err) + require.NotNil(t, accessTokensUserSetting) + require.Equal(t, storepb.UserSettingKey_USER_SETTING_ACCESS_TOKENS, accessTokensUserSetting.Key) + require.Equal(t, user.ID, accessTokensUserSetting.UserId) + require.Equal(t, 1, len(accessTokensUserSetting.GetAccessTokensUserSetting().AccessTokens)) + userSettings, err = ts.ListUserSettings(ctx, &store.FindUserSetting{ + UserID: &user.ID, + }) + require.NoError(t, err) + require.Equal(t, 1, len(userSettings)) + require.Equal(t, accessTokensUserSetting, userSettings[0]) + accessTokensUserSetting, err = ts.GetUserSetting(ctx, &store.FindUserSetting{ + UserID: &user.ID, + Key: storepb.UserSettingKey_USER_SETTING_ACCESS_TOKENS, + }) + require.NoError(t, err) + require.NotNil(t, accessTokensUserSetting) + require.Equal(t, 1, len(accessTokensUserSetting.GetAccessTokensUserSetting().AccessTokens)) + require.Equal(t, "test_access_token", accessTokensUserSetting.GetAccessTokensUserSetting().AccessTokens[0].AccessToken) + accessTokensUserSetting, err = ts.UpsertUserSetting(ctx, &storepb.UserSetting{ + UserId: user.ID, + Key: storepb.UserSettingKey_USER_SETTING_ACCESS_TOKENS, + Value: &storepb.UserSetting_AccessTokensUserSetting{ + AccessTokensUserSetting: &storepb.AccessTokensUserSetting{ + AccessTokens: []*storepb.AccessTokensUserSetting_AccessToken{ + { + AccessToken: "test_access_token", + }, + { + AccessToken: "test_access_token2", + }, + }, + }, + }, + }) + require.NoError(t, err) + require.NotNil(t, accessTokensUserSetting) + require.Equal(t, 2, len(accessTokensUserSetting.GetAccessTokensUserSetting().AccessTokens)) +}