diff --git a/proto/gen/store/README.md b/proto/gen/store/README.md index 8c058973..bd171c88 100644 --- a/proto/gen/store/README.md +++ b/proto/gen/store/README.md @@ -9,6 +9,8 @@ - [ActivityVersionUpdatePayload](#memos-store-ActivityVersionUpdatePayload) - [store/common.proto](#store_common-proto) + - [RowStatus](#memos-store-RowStatus) + - [store/inbox.proto](#store_inbox-proto) - [InboxMessage](#memos-store-InboxMessage) @@ -26,6 +28,9 @@ - [UserSettingKey](#memos-store-UserSettingKey) +- [store/webhook.proto](#store_webhook-proto) + - [Webhook](#memos-store-Webhook) + - [Scalar Value Types](#scalar-value-types) @@ -101,6 +106,19 @@ + + + +### RowStatus + + +| Name | Number | Description | +| ---- | ------ | ----------- | +| ROW_STATUS_UNSPECIFIED | 0 | | +| NORMAL | 1 | | +| ARCHIVED | 2 | | + + @@ -275,6 +293,43 @@ + +
+ +## store/webhook.proto + + + + + +### Webhook + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| id | [int32](#int32) | | | +| created_ts | [int64](#int64) | | | +| updated_ts | [int64](#int64) | | | +| creator_id | [int32](#int32) | | | +| row_status | [RowStatus](#memos-store-RowStatus) | | | +| name | [string](#string) | | | +| url | [string](#string) | | | + + + + + + + + + + + + + + + ## Scalar Value Types | .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby | diff --git a/proto/gen/store/common.pb.go b/proto/gen/store/common.pb.go index 0ee5f9d4..ecf2b661 100644 --- a/proto/gen/store/common.pb.go +++ b/proto/gen/store/common.pb.go @@ -10,6 +10,7 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" + sync "sync" ) const ( @@ -19,25 +20,93 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type RowStatus int32 + +const ( + RowStatus_ROW_STATUS_UNSPECIFIED RowStatus = 0 + RowStatus_NORMAL RowStatus = 1 + RowStatus_ARCHIVED RowStatus = 2 +) + +// Enum value maps for RowStatus. +var ( + RowStatus_name = map[int32]string{ + 0: "ROW_STATUS_UNSPECIFIED", + 1: "NORMAL", + 2: "ARCHIVED", + } + RowStatus_value = map[string]int32{ + "ROW_STATUS_UNSPECIFIED": 0, + "NORMAL": 1, + "ARCHIVED": 2, + } +) + +func (x RowStatus) Enum() *RowStatus { + p := new(RowStatus) + *p = x + return p +} + +func (x RowStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (RowStatus) Descriptor() protoreflect.EnumDescriptor { + return file_store_common_proto_enumTypes[0].Descriptor() +} + +func (RowStatus) Type() protoreflect.EnumType { + return &file_store_common_proto_enumTypes[0] +} + +func (x RowStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use RowStatus.Descriptor instead. +func (RowStatus) EnumDescriptor() ([]byte, []int) { + return file_store_common_proto_rawDescGZIP(), []int{0} +} + var File_store_common_proto protoreflect.FileDescriptor var file_store_common_proto_rawDesc = []byte{ 0x0a, 0x12, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x42, 0x96, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, - 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0xa2, - 0x02, 0x03, 0x4d, 0x53, 0x58, 0xaa, 0x02, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x53, 0x74, - 0x6f, 0x72, 0x65, 0xca, 0x02, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x53, 0x74, 0x6f, 0x72, - 0x65, 0xe2, 0x02, 0x17, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x5c, - 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x4d, 0x65, - 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x65, 0x2a, 0x41, 0x0a, 0x09, 0x52, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, + 0x0a, 0x16, 0x52, 0x4f, 0x57, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, + 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, + 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x52, 0x43, 0x48, 0x49, 0x56, + 0x45, 0x44, 0x10, 0x02, 0x42, 0x96, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d, + 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x65, 0x6d, + 0x6f, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x73, 0x74, 0x6f, + 0x72, 0x65, 0xa2, 0x02, 0x03, 0x4d, 0x53, 0x58, 0xaa, 0x02, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x73, + 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xca, 0x02, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x53, + 0x74, 0x6f, 0x72, 0x65, 0xe2, 0x02, 0x17, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x53, 0x74, 0x6f, + 0x72, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, + 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } -var file_store_common_proto_goTypes = []interface{}{} +var ( + file_store_common_proto_rawDescOnce sync.Once + file_store_common_proto_rawDescData = file_store_common_proto_rawDesc +) + +func file_store_common_proto_rawDescGZIP() []byte { + file_store_common_proto_rawDescOnce.Do(func() { + file_store_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_store_common_proto_rawDescData) + }) + return file_store_common_proto_rawDescData +} + +var file_store_common_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_store_common_proto_goTypes = []interface{}{ + (RowStatus)(0), // 0: memos.store.RowStatus +} var file_store_common_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type @@ -56,13 +125,14 @@ func file_store_common_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_store_common_proto_rawDesc, - NumEnums: 0, + NumEnums: 1, NumMessages: 0, NumExtensions: 0, NumServices: 0, }, GoTypes: file_store_common_proto_goTypes, DependencyIndexes: file_store_common_proto_depIdxs, + EnumInfos: file_store_common_proto_enumTypes, }.Build() File_store_common_proto = out.File file_store_common_proto_rawDesc = nil diff --git a/proto/gen/store/webhook.pb.go b/proto/gen/store/webhook.pb.go new file mode 100644 index 00000000..d85d4025 --- /dev/null +++ b/proto/gen/store/webhook.pb.go @@ -0,0 +1,214 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: store/webhook.proto + +package store + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + 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 Webhook struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + CreatedTs int64 `protobuf:"varint,2,opt,name=created_ts,json=createdTs,proto3" json:"created_ts,omitempty"` + UpdatedTs int64 `protobuf:"varint,3,opt,name=updated_ts,json=updatedTs,proto3" json:"updated_ts,omitempty"` + CreatorId int32 `protobuf:"varint,4,opt,name=creator_id,json=creatorId,proto3" json:"creator_id,omitempty"` + RowStatus RowStatus `protobuf:"varint,5,opt,name=row_status,json=rowStatus,proto3,enum=memos.store.RowStatus" json:"row_status,omitempty"` + Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"` + Url string `protobuf:"bytes,7,opt,name=url,proto3" json:"url,omitempty"` +} + +func (x *Webhook) Reset() { + *x = Webhook{} + if protoimpl.UnsafeEnabled { + mi := &file_store_webhook_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Webhook) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Webhook) ProtoMessage() {} + +func (x *Webhook) ProtoReflect() protoreflect.Message { + mi := &file_store_webhook_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 Webhook.ProtoReflect.Descriptor instead. +func (*Webhook) Descriptor() ([]byte, []int) { + return file_store_webhook_proto_rawDescGZIP(), []int{0} +} + +func (x *Webhook) GetId() int32 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *Webhook) GetCreatedTs() int64 { + if x != nil { + return x.CreatedTs + } + return 0 +} + +func (x *Webhook) GetUpdatedTs() int64 { + if x != nil { + return x.UpdatedTs + } + return 0 +} + +func (x *Webhook) GetCreatorId() int32 { + if x != nil { + return x.CreatorId + } + return 0 +} + +func (x *Webhook) GetRowStatus() RowStatus { + if x != nil { + return x.RowStatus + } + return RowStatus_ROW_STATUS_UNSPECIFIED +} + +func (x *Webhook) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Webhook) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +var File_store_webhook_proto protoreflect.FileDescriptor + +var file_store_webhook_proto_rawDesc = []byte{ + 0x0a, 0x13, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x77, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, + 0x72, 0x65, 0x1a, 0x12, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd3, 0x01, 0x0a, 0x07, 0x57, 0x65, 0x62, 0x68, 0x6f, + 0x6f, 0x6b, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x54, + 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x73, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x54, 0x73, + 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x64, 0x12, + 0x35, 0x0a, 0x0a, 0x72, 0x6f, 0x77, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x2e, 0x52, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x09, 0x72, 0x6f, 0x77, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, + 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x42, 0x97, 0x01, 0x0a, + 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x42, 0x0c, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x73, 0x65, + 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0xa2, 0x02, 0x03, 0x4d, 0x53, + 0x58, 0xaa, 0x02, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xca, + 0x02, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xe2, 0x02, 0x17, + 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x3a, + 0x3a, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_store_webhook_proto_rawDescOnce sync.Once + file_store_webhook_proto_rawDescData = file_store_webhook_proto_rawDesc +) + +func file_store_webhook_proto_rawDescGZIP() []byte { + file_store_webhook_proto_rawDescOnce.Do(func() { + file_store_webhook_proto_rawDescData = protoimpl.X.CompressGZIP(file_store_webhook_proto_rawDescData) + }) + return file_store_webhook_proto_rawDescData +} + +var file_store_webhook_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_store_webhook_proto_goTypes = []interface{}{ + (*Webhook)(nil), // 0: memos.store.Webhook + (RowStatus)(0), // 1: memos.store.RowStatus +} +var file_store_webhook_proto_depIdxs = []int32{ + 1, // 0: memos.store.Webhook.row_status:type_name -> memos.store.RowStatus + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_store_webhook_proto_init() } +func file_store_webhook_proto_init() { + if File_store_webhook_proto != nil { + return + } + file_store_common_proto_init() + if !protoimpl.UnsafeEnabled { + file_store_webhook_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Webhook); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_store_webhook_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_store_webhook_proto_goTypes, + DependencyIndexes: file_store_webhook_proto_depIdxs, + MessageInfos: file_store_webhook_proto_msgTypes, + }.Build() + File_store_webhook_proto = out.File + file_store_webhook_proto_rawDesc = nil + file_store_webhook_proto_goTypes = nil + file_store_webhook_proto_depIdxs = nil +} diff --git a/proto/store/common.proto b/proto/store/common.proto index 5990f042..147cfd31 100644 --- a/proto/store/common.proto +++ b/proto/store/common.proto @@ -3,3 +3,11 @@ syntax = "proto3"; package memos.store; option go_package = "gen/store"; + +enum RowStatus { + ROW_STATUS_UNSPECIFIED = 0; + + NORMAL = 1; + + ARCHIVED = 2; +} diff --git a/proto/store/webhook.proto b/proto/store/webhook.proto new file mode 100644 index 00000000..04627d7e --- /dev/null +++ b/proto/store/webhook.proto @@ -0,0 +1,23 @@ +syntax = "proto3"; + +package memos.store; + +import "store/common.proto"; + +option go_package = "gen/store"; + +message Webhook { + int32 id = 1; + + int64 created_ts = 2; + + int64 updated_ts = 3; + + int32 creator_id = 4; + + RowStatus row_status = 5; + + string name = 6; + + string url = 7; +} diff --git a/store/db/mysql/migration/dev/LATEST__SCHEMA.sql b/store/db/mysql/migration/dev/LATEST__SCHEMA.sql index 005595bc..707dc381 100644 --- a/store/db/mysql/migration/dev/LATEST__SCHEMA.sql +++ b/store/db/mysql/migration/dev/LATEST__SCHEMA.sql @@ -133,3 +133,14 @@ CREATE TABLE `inbox` ( `status` TEXT NOT NULL, `message` TEXT NOT NULL ); + +-- webhook +CREATE TABLE `webhook` ( + `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + `created_ts` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_ts` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `row_status` TEXT NOT NULL DEFAULT 'NORMAL', + `creator_id` INT NOT NULL, + `name` TEXT NOT NULL, + `url` TEXT NOT NULL +); diff --git a/store/db/mysql/storage.go b/store/db/mysql/storage.go index 36507ee6..3eb1ce83 100644 --- a/store/db/mysql/storage.go +++ b/store/db/mysql/storage.go @@ -68,18 +68,6 @@ func (d *DB) ListStorages(ctx context.Context, find *store.FindStorage) ([]*stor return list, nil } -func (d *DB) GetStorage(ctx context.Context, find *store.FindStorage) (*store.Storage, error) { - list, err := d.ListStorages(ctx, find) - if err != nil { - return nil, err - } - if len(list) == 0 { - return nil, nil - } - - return list[0], nil -} - func (d *DB) UpdateStorage(ctx context.Context, update *store.UpdateStorage) (*store.Storage, error) { set, args := []string{}, []any{} if update.Name != nil { diff --git a/store/db/mysql/webhook.go b/store/db/mysql/webhook.go new file mode 100644 index 00000000..f01ab294 --- /dev/null +++ b/store/db/mysql/webhook.go @@ -0,0 +1,121 @@ +package mysql + +import ( + "context" + "strings" + + storepb "github.com/usememos/memos/proto/gen/store" + "github.com/usememos/memos/store" +) + +func (d *DB) CreateWebhook(ctx context.Context, create *storepb.Webhook) (*storepb.Webhook, error) { + fields := []string{"`name`", "`url`", "`creator_id`"} + placeholder := []string{"?", "?", "?"} + args := []any{create.Name, create.Url, create.CreatorId} + + if create.Id != 0 { + fields = append(fields, "`id`") + placeholder = append(placeholder, "?") + args = append(args, create.Id) + } + + stmt := "INSERT INTO `webhook` (" + strings.Join(fields, ", ") + ") VALUES (" + strings.Join(placeholder, ", ") + ")" + result, err := d.db.ExecContext(ctx, stmt, args...) + if err != nil { + return nil, err + } + + id, err := result.LastInsertId() + if err != nil { + return nil, err + } + + create.Id = int32(id) + return create, nil +} + +func (d *DB) ListWebhooks(ctx context.Context, find *store.FindWebhook) ([]*storepb.Webhook, error) { + where, args := []string{"1 = 1"}, []any{} + if find.ID != nil { + where, args = append(where, "`id` = ?"), append(args, *find.ID) + } + if find.CreatorID != nil { + where, args = append(where, "`creator_id` = ?"), append(args, *find.CreatorID) + } + + rows, err := d.db.QueryContext(ctx, "SELECT `id`, `created_ts`, `updated_ts`, `row_status`, `creator_id`, `name`, `url` FROM `webhook` WHERE "+strings.Join(where, " AND ")+" ORDER BY `id` DESC", + args..., + ) + if err != nil { + return nil, err + } + defer rows.Close() + + list := []*storepb.Webhook{} + for rows.Next() { + webhook := &storepb.Webhook{} + var rowStatus string + if err := rows.Scan( + &webhook.Id, + &webhook.CreatedTs, + &webhook.UpdatedTs, + &rowStatus, + &webhook.CreatorId, + &webhook.Name, + &webhook.Url, + ); err != nil { + return nil, err + } + webhook.RowStatus = storepb.RowStatus(storepb.RowStatus_value[rowStatus]) + list = append(list, webhook) + } + + if err := rows.Err(); err != nil { + return nil, err + } + + return list, nil +} + +func (d *DB) GetWebhook(ctx context.Context, find *store.FindWebhook) (*storepb.Webhook, error) { + list, err := d.ListWebhooks(ctx, find) + if err != nil { + return nil, err + } + if len(list) == 0 { + return nil, nil + } + return list[0], nil +} + +func (d *DB) UpdateWebhook(ctx context.Context, update *store.UpdateWebhook) (*storepb.Webhook, error) { + set, args := []string{}, []any{} + if update.RowStatus != nil { + set, args = append(set, "`row_status` = ?"), append(args, update.RowStatus.String()) + } + if update.Name != nil { + set, args = append(set, "`name` = ?"), append(args, *update.Name) + } + if update.URL != nil { + set, args = append(set, "`url` = ?"), append(args, *update.URL) + } + args = append(args, update.ID) + + stmt := "UPDATE `webhook` SET " + strings.Join(set, ", ") + " WHERE `id` = ?" + _, err := d.db.ExecContext(ctx, stmt, args...) + if err != nil { + return nil, err + } + + webhook, err := d.GetWebhook(ctx, &store.FindWebhook{ID: &update.ID}) + if err != nil { + return nil, err + } + + return webhook, nil +} + +func (d *DB) DeleteWebhook(ctx context.Context, delete *store.DeleteWebhook) error { + _, err := d.db.ExecContext(ctx, "DELETE FROM `webhook` WHERE `id` = ?", delete.ID) + return err +} diff --git a/store/db/sqlite/idp.go b/store/db/sqlite/idp.go index 27b864b7..7e66b6ec 100644 --- a/store/db/sqlite/idp.go +++ b/store/db/sqlite/idp.go @@ -97,19 +97,6 @@ func (d *DB) ListIdentityProviders(ctx context.Context, find *store.FindIdentity return identityProviders, nil } -func (d *DB) GetIdentityProvider(ctx context.Context, find *store.FindIdentityProvider) (*store.IdentityProvider, error) { - list, err := d.ListIdentityProviders(ctx, find) - if err != nil { - return nil, err - } - if len(list) == 0 { - return nil, nil - } - - identityProvider := list[0] - return identityProvider, nil -} - func (d *DB) UpdateIdentityProvider(ctx context.Context, update *store.UpdateIdentityProvider) (*store.IdentityProvider, error) { set, args := []string{}, []any{} if v := update.Name; v != nil { diff --git a/store/db/sqlite/migration/dev/LATEST__SCHEMA.sql b/store/db/sqlite/migration/dev/LATEST__SCHEMA.sql index 597d6317..61f2685d 100644 --- a/store/db/sqlite/migration/dev/LATEST__SCHEMA.sql +++ b/store/db/sqlite/migration/dev/LATEST__SCHEMA.sql @@ -144,3 +144,16 @@ CREATE TABLE inbox ( status TEXT NOT NULL, message TEXT NOT NULL DEFAULT '{}' ); + +-- webhook +CREATE TABLE webhook ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')), + updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')), + row_status TEXT NOT NULL CHECK (row_status IN ('NORMAL', 'ARCHIVED')) DEFAULT 'NORMAL', + creator_id INTEGER NOT NULL, + name TEXT NOT NULL, + url TEXT NOT NULL +); + +CREATE INDEX idx_webhook_creator_id ON webhook (creator_id); diff --git a/store/db/sqlite/storage.go b/store/db/sqlite/storage.go index 5d4d009a..14579c0c 100644 --- a/store/db/sqlite/storage.go +++ b/store/db/sqlite/storage.go @@ -72,18 +72,6 @@ func (d *DB) ListStorages(ctx context.Context, find *store.FindStorage) ([]*stor return list, nil } -func (d *DB) GetStorage(ctx context.Context, find *store.FindStorage) (*store.Storage, error) { - list, err := d.ListStorages(ctx, find) - if err != nil { - return nil, err - } - if len(list) == 0 { - return nil, nil - } - - return list[0], nil -} - func (d *DB) UpdateStorage(ctx context.Context, update *store.UpdateStorage) (*store.Storage, error) { set, args := []string{}, []any{} if update.Name != nil { diff --git a/store/db/sqlite/webhook.go b/store/db/sqlite/webhook.go new file mode 100644 index 00000000..5443f0fa --- /dev/null +++ b/store/db/sqlite/webhook.go @@ -0,0 +1,126 @@ +package sqlite + +import ( + "context" + "strings" + + storepb "github.com/usememos/memos/proto/gen/store" + "github.com/usememos/memos/store" +) + +func (d *DB) CreateWebhook(ctx context.Context, create *storepb.Webhook) (*storepb.Webhook, error) { + fields := []string{"`name`", "`url`", "`creator_id`"} + placeholder := []string{"?", "?", "?"} + args := []any{create.Name, create.Url, create.CreatorId} + + if create.Id != 0 { + fields = append(fields, "`id`") + placeholder = append(placeholder, "?") + args = append(args, create.Id) + } + + stmt := "INSERT INTO `webhook` (" + strings.Join(fields, ", ") + ") VALUES (" + strings.Join(placeholder, ", ") + ") RETURNING `id`, `created_ts`, `updated_ts`, `row_status`" + var rowStatus string + if err := d.db.QueryRowContext(ctx, stmt, args...).Scan( + &create.Id, + &create.CreatedTs, + &create.UpdatedTs, + &rowStatus, + ); err != nil { + return nil, err + } + + create.RowStatus = storepb.RowStatus(storepb.RowStatus_value[rowStatus]) + webhook := create + return webhook, nil +} + +func (d *DB) ListWebhooks(ctx context.Context, find *store.FindWebhook) ([]*storepb.Webhook, error) { + where, args := []string{"1 = 1"}, []any{} + if find.ID != nil { + where, args = append(where, "id = ?"), append(args, *find.ID) + } + if find.CreatorID != nil { + where, args = append(where, "creator_id = ?"), append(args, *find.CreatorID) + } + + rows, err := d.db.QueryContext(ctx, ` + SELECT + id, + created_ts, + updated_ts, + row_status, + creator_id, + name, + url + FROM webhook + WHERE `+strings.Join(where, " AND ")+` + ORDER BY id DESC`, + args..., + ) + if err != nil { + return nil, err + } + defer rows.Close() + + list := []*storepb.Webhook{} + for rows.Next() { + webhook := &storepb.Webhook{} + var rowStatus string + if err := rows.Scan( + &webhook.Id, + &webhook.CreatedTs, + &webhook.UpdatedTs, + &rowStatus, + &webhook.CreatorId, + &webhook.Name, + &webhook.Url, + ); err != nil { + return nil, err + } + webhook.RowStatus = storepb.RowStatus(storepb.RowStatus_value[rowStatus]) + list = append(list, webhook) + } + + if err := rows.Err(); err != nil { + return nil, err + } + + return list, nil +} + +func (d *DB) UpdateWebhook(ctx context.Context, update *store.UpdateWebhook) (*storepb.Webhook, error) { + set, args := []string{}, []any{} + if update.RowStatus != nil { + set, args = append(set, "row_status = ?"), append(args, update.RowStatus.String()) + } + if update.Name != nil { + set, args = append(set, "name = ?"), append(args, *update.Name) + } + if update.URL != nil { + set, args = append(set, "url = ?"), append(args, *update.URL) + } + args = append(args, update.ID) + + stmt := "UPDATE `webhook` SET " + strings.Join(set, ", ") + " WHERE `id` = ? RETURNING `id`, `created_ts`, `updated_ts`, `row_status`, `creator_id`, `name`, `url`" + webhook := &storepb.Webhook{} + var rowStatus string + if err := d.db.QueryRowContext(ctx, stmt, args...).Scan( + &webhook.Id, + &webhook.CreatedTs, + &webhook.UpdatedTs, + &rowStatus, + &webhook.CreatorId, + &webhook.Name, + &webhook.Url, + ); err != nil { + return nil, err + } + webhook.RowStatus = storepb.RowStatus(storepb.RowStatus_value[rowStatus]) + return webhook, nil +} + +func (d *DB) DeleteWebhook(ctx context.Context, delete *store.DeleteWebhook) error { + _, err := d.db.ExecContext(ctx, "DELETE FROM `webhook` WHERE `id` = ?", delete.ID) + return err +} diff --git a/store/driver.go b/store/driver.go index 6c090dba..f5fcec49 100644 --- a/store/driver.go +++ b/store/driver.go @@ -70,7 +70,6 @@ type Driver interface { // IdentityProvider model related methods. CreateIdentityProvider(ctx context.Context, create *IdentityProvider) (*IdentityProvider, error) ListIdentityProviders(ctx context.Context, find *FindIdentityProvider) ([]*IdentityProvider, error) - GetIdentityProvider(ctx context.Context, find *FindIdentityProvider) (*IdentityProvider, error) UpdateIdentityProvider(ctx context.Context, update *UpdateIdentityProvider) (*IdentityProvider, error) DeleteIdentityProvider(ctx context.Context, delete *DeleteIdentityProvider) error @@ -82,7 +81,6 @@ type Driver interface { // Storage model related methods. CreateStorage(ctx context.Context, create *Storage) (*Storage, error) ListStorages(ctx context.Context, find *FindStorage) ([]*Storage, error) - GetStorage(ctx context.Context, find *FindStorage) (*Storage, error) UpdateStorage(ctx context.Context, update *UpdateStorage) (*Storage, error) DeleteStorage(ctx context.Context, delete *DeleteStorage) error @@ -91,4 +89,10 @@ type Driver interface { ListInboxes(ctx context.Context, find *FindInbox) ([]*Inbox, error) UpdateInbox(ctx context.Context, update *UpdateInbox) (*Inbox, error) DeleteInbox(ctx context.Context, delete *DeleteInbox) error + + // Webhook model related methods. + CreateWebhook(ctx context.Context, create *storepb.Webhook) (*storepb.Webhook, error) + ListWebhooks(ctx context.Context, find *FindWebhook) ([]*storepb.Webhook, error) + UpdateWebhook(ctx context.Context, update *UpdateWebhook) (*storepb.Webhook, error) + DeleteWebhook(ctx context.Context, delete *DeleteWebhook) error } diff --git a/store/webhook.go b/store/webhook.go new file mode 100644 index 00000000..2adf3236 --- /dev/null +++ b/store/webhook.go @@ -0,0 +1,50 @@ +package store + +import ( + "context" + + storepb "github.com/usememos/memos/proto/gen/store" +) + +type FindWebhook struct { + ID *int32 + CreatorID *int32 +} + +type UpdateWebhook struct { + ID int32 + RowStatus *storepb.RowStatus + Name *string + URL *string +} + +type DeleteWebhook struct { + ID int32 +} + +func (s *Store) CreateWebhook(ctx context.Context, create *storepb.Webhook) (*storepb.Webhook, error) { + return s.driver.CreateWebhook(ctx, create) +} + +func (s *Store) ListWebhooks(ctx context.Context, find *FindWebhook) ([]*storepb.Webhook, error) { + return s.driver.ListWebhooks(ctx, find) +} + +func (s *Store) GetWebhooks(ctx context.Context, find *FindWebhook) (*storepb.Webhook, error) { + list, err := s.ListWebhooks(ctx, find) + if err != nil { + return nil, err + } + if len(list) == 0 { + return nil, nil + } + return list[0], nil +} + +func (s *Store) UpdateWebhook(ctx context.Context, update *UpdateWebhook) (*storepb.Webhook, error) { + return s.driver.UpdateWebhook(ctx, update) +} + +func (s *Store) DeleteWebhook(ctx context.Context, delete *DeleteWebhook) error { + return s.driver.DeleteWebhook(ctx, delete) +} diff --git a/test/store/webhook_test.go b/test/store/webhook_test.go new file mode 100644 index 00000000..06810139 --- /dev/null +++ b/test/store/webhook_test.go @@ -0,0 +1,50 @@ +package teststore + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + storepb "github.com/usememos/memos/proto/gen/store" + "github.com/usememos/memos/store" +) + +func TestWebhookStore(t *testing.T) { + ctx := context.Background() + ts := NewTestingStore(ctx, t) + user, err := createTestingHostUser(ctx, ts) + require.NoError(t, err) + webhook, err := ts.CreateWebhook(ctx, &storepb.Webhook{ + CreatorId: user.ID, + Name: "test_webhook", + Url: "https://example.com", + RowStatus: storepb.RowStatus_NORMAL, + }) + require.NoError(t, err) + require.Equal(t, "test_webhook", webhook.Name) + require.Equal(t, user.ID, webhook.CreatorId) + webhooks, err := ts.ListWebhooks(ctx, &store.FindWebhook{ + CreatorID: &user.ID, + }) + require.NoError(t, err) + require.Equal(t, 1, len(webhooks)) + require.Equal(t, webhook, webhooks[0]) + newName := "test_webhook_new" + updatedWebhook, err := ts.UpdateWebhook(ctx, &store.UpdateWebhook{ + ID: webhook.Id, + Name: &newName, + }) + require.NoError(t, err) + require.Equal(t, newName, updatedWebhook.Name) + require.Equal(t, webhook.CreatorId, updatedWebhook.CreatorId) + err = ts.DeleteWebhook(ctx, &store.DeleteWebhook{ + ID: webhook.Id, + }) + require.NoError(t, err) + webhooks, err = ts.ListWebhooks(ctx, &store.FindWebhook{ + CreatorID: &user.ID, + }) + require.NoError(t, err) + require.Equal(t, 0, len(webhooks)) +}