mirror of https://github.com/usememos/memos.git
refactor(api): migrate inbox functionality to user notifications
- Remove standalone InboxService and move functionality to UserService - Rename inbox to user notifications for better API consistency - Add ListUserNotifications, UpdateUserNotification, DeleteUserNotification methods - Update frontend components to use new notification endpoints - Update store layer to support new notification model 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
e915e3a46b
commit
bc1550e926
|
|
@ -61,8 +61,6 @@ message Activity {
|
|||
TYPE_UNSPECIFIED = 0;
|
||||
// Memo comment activity.
|
||||
MEMO_COMMENT = 1;
|
||||
// Version update activity.
|
||||
VERSION_UPDATE = 2;
|
||||
}
|
||||
|
||||
// Activity levels.
|
||||
|
|
|
|||
|
|
@ -1,149 +0,0 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package memos.api.v1;
|
||||
|
||||
import "google/api/annotations.proto";
|
||||
import "google/api/client.proto";
|
||||
import "google/api/field_behavior.proto";
|
||||
import "google/api/resource.proto";
|
||||
import "google/protobuf/empty.proto";
|
||||
import "google/protobuf/field_mask.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
option go_package = "gen/api/v1";
|
||||
|
||||
service InboxService {
|
||||
// ListInboxes lists inboxes for a user.
|
||||
rpc ListInboxes(ListInboxesRequest) returns (ListInboxesResponse) {
|
||||
option (google.api.http) = {get: "/api/v1/{parent=users/*}/inboxes"};
|
||||
option (google.api.method_signature) = "parent";
|
||||
}
|
||||
// UpdateInbox updates an inbox.
|
||||
rpc UpdateInbox(UpdateInboxRequest) returns (Inbox) {
|
||||
option (google.api.http) = {
|
||||
patch: "/api/v1/{inbox.name=inboxes/*}"
|
||||
body: "inbox"
|
||||
};
|
||||
option (google.api.method_signature) = "inbox,update_mask";
|
||||
}
|
||||
// DeleteInbox deletes an inbox.
|
||||
rpc DeleteInbox(DeleteInboxRequest) returns (google.protobuf.Empty) {
|
||||
option (google.api.http) = {delete: "/api/v1/{name=inboxes/*}"};
|
||||
option (google.api.method_signature) = "name";
|
||||
}
|
||||
}
|
||||
|
||||
message Inbox {
|
||||
option (google.api.resource) = {
|
||||
type: "memos.api.v1/Inbox"
|
||||
pattern: "inboxes/{inbox}"
|
||||
name_field: "name"
|
||||
singular: "inbox"
|
||||
plural: "inboxes"
|
||||
};
|
||||
|
||||
// The resource name of the inbox.
|
||||
// Format: inboxes/{inbox}
|
||||
string name = 1 [(google.api.field_behavior) = IDENTIFIER];
|
||||
|
||||
// The sender of the inbox notification.
|
||||
// Format: users/{user}
|
||||
string sender = 2 [(google.api.field_behavior) = OUTPUT_ONLY];
|
||||
|
||||
// The receiver of the inbox notification.
|
||||
// Format: users/{user}
|
||||
string receiver = 3 [(google.api.field_behavior) = OUTPUT_ONLY];
|
||||
|
||||
// The status of the inbox notification.
|
||||
Status status = 4 [(google.api.field_behavior) = OPTIONAL];
|
||||
|
||||
// Output only. The creation timestamp.
|
||||
google.protobuf.Timestamp create_time = 5 [(google.api.field_behavior) = OUTPUT_ONLY];
|
||||
|
||||
// The type of the inbox notification.
|
||||
Type type = 6 [(google.api.field_behavior) = OUTPUT_ONLY];
|
||||
|
||||
// Optional. The activity ID associated with this inbox notification.
|
||||
optional int32 activity_id = 7 [(google.api.field_behavior) = OPTIONAL];
|
||||
|
||||
// Status enumeration for inbox notifications.
|
||||
enum Status {
|
||||
// Unspecified status.
|
||||
STATUS_UNSPECIFIED = 0;
|
||||
// The notification is unread.
|
||||
UNREAD = 1;
|
||||
// The notification is archived.
|
||||
ARCHIVED = 2;
|
||||
}
|
||||
|
||||
// Type enumeration for inbox notifications.
|
||||
enum Type {
|
||||
// Unspecified type.
|
||||
TYPE_UNSPECIFIED = 0;
|
||||
// Memo comment notification.
|
||||
MEMO_COMMENT = 1;
|
||||
// Version update notification.
|
||||
VERSION_UPDATE = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message ListInboxesRequest {
|
||||
// Required. The parent resource whose inboxes will be listed.
|
||||
// Format: users/{user}
|
||||
string parent = 1 [
|
||||
(google.api.field_behavior) = REQUIRED,
|
||||
(google.api.resource_reference) = {type: "memos.api.v1/User"}
|
||||
];
|
||||
|
||||
// Optional. The maximum number of inboxes to return.
|
||||
// The service may return fewer than this value.
|
||||
// If unspecified, at most 50 inboxes will be returned.
|
||||
// The maximum value is 1000; values above 1000 will be coerced to 1000.
|
||||
int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];
|
||||
|
||||
// Optional. A page token, received from a previous `ListInboxes` call.
|
||||
// Provide this to retrieve the subsequent page.
|
||||
string page_token = 3 [(google.api.field_behavior) = OPTIONAL];
|
||||
|
||||
// Optional. Filter to apply to the list results.
|
||||
// Example: "status=UNREAD" or "type=MEMO_COMMENT"
|
||||
// Supported operators: =, !=
|
||||
// Supported fields: status, type, sender, create_time
|
||||
string filter = 4 [(google.api.field_behavior) = OPTIONAL];
|
||||
|
||||
// Optional. The order to sort results by.
|
||||
// Example: "create_time desc" or "status asc"
|
||||
string order_by = 5 [(google.api.field_behavior) = OPTIONAL];
|
||||
}
|
||||
|
||||
message ListInboxesResponse {
|
||||
// The list of inboxes.
|
||||
repeated Inbox inboxes = 1;
|
||||
|
||||
// A token that can be sent as `page_token` to retrieve the next page.
|
||||
// If this field is omitted, there are no subsequent pages.
|
||||
string next_page_token = 2;
|
||||
|
||||
// The total count of inboxes (may be approximate).
|
||||
int32 total_size = 3;
|
||||
}
|
||||
|
||||
message UpdateInboxRequest {
|
||||
// Required. The inbox to update.
|
||||
Inbox inbox = 1 [(google.api.field_behavior) = REQUIRED];
|
||||
|
||||
// Required. The list of fields to update.
|
||||
google.protobuf.FieldMask update_mask = 2 [(google.api.field_behavior) = REQUIRED];
|
||||
|
||||
// Optional. If set to true, allows updating missing fields.
|
||||
bool allow_missing = 3 [(google.api.field_behavior) = OPTIONAL];
|
||||
}
|
||||
|
||||
message DeleteInboxRequest {
|
||||
// Required. The resource name of the inbox to delete.
|
||||
// Format: inboxes/{inbox}
|
||||
string name = 1 [
|
||||
(google.api.field_behavior) = REQUIRED,
|
||||
(google.api.resource_reference) = {type: "memos.api.v1/Inbox"}
|
||||
];
|
||||
}
|
||||
|
|
@ -153,6 +153,27 @@ service UserService {
|
|||
option (google.api.http) = {delete: "/api/v1/{name=users/*/webhooks/*}"};
|
||||
option (google.api.method_signature) = "name";
|
||||
}
|
||||
|
||||
// ListUserNotifications lists notifications for a user.
|
||||
rpc ListUserNotifications(ListUserNotificationsRequest) returns (ListUserNotificationsResponse) {
|
||||
option (google.api.http) = {get: "/api/v1/{parent=users/*}/notifications"};
|
||||
option (google.api.method_signature) = "parent";
|
||||
}
|
||||
|
||||
// UpdateUserNotification updates a notification.
|
||||
rpc UpdateUserNotification(UpdateUserNotificationRequest) returns (UserNotification) {
|
||||
option (google.api.http) = {
|
||||
patch: "/api/v1/{notification.name=users/*/notifications/*}"
|
||||
body: "notification"
|
||||
};
|
||||
option (google.api.method_signature) = "notification,update_mask";
|
||||
}
|
||||
|
||||
// DeleteUserNotification deletes a notification.
|
||||
rpc DeleteUserNotification(DeleteUserNotificationRequest) returns (google.protobuf.Empty) {
|
||||
option (google.api.http) = {delete: "/api/v1/{name=users/*/notifications/*}"};
|
||||
option (google.api.method_signature) = "name";
|
||||
}
|
||||
}
|
||||
|
||||
message User {
|
||||
|
|
@ -672,3 +693,81 @@ message DeleteUserWebhookRequest {
|
|||
// Format: users/{user}/webhooks/{webhook}
|
||||
string name = 1 [(google.api.field_behavior) = REQUIRED];
|
||||
}
|
||||
|
||||
message UserNotification {
|
||||
option (google.api.resource) = {
|
||||
type: "memos.api.v1/UserNotification"
|
||||
pattern: "users/{user}/notifications/{notification}"
|
||||
name_field: "name"
|
||||
singular: "notification"
|
||||
plural: "notifications"
|
||||
};
|
||||
|
||||
// The resource name of the notification.
|
||||
// Format: users/{user}/notifications/{notification}
|
||||
string name = 1 [
|
||||
(google.api.field_behavior) = OUTPUT_ONLY,
|
||||
(google.api.field_behavior) = IDENTIFIER
|
||||
];
|
||||
|
||||
// The sender of the notification.
|
||||
// Format: users/{user}
|
||||
string sender = 2 [
|
||||
(google.api.field_behavior) = OUTPUT_ONLY,
|
||||
(google.api.resource_reference) = {type: "memos.api.v1/User"}
|
||||
];
|
||||
|
||||
// The status of the notification.
|
||||
Status status = 3 [(google.api.field_behavior) = OPTIONAL];
|
||||
|
||||
// The creation timestamp.
|
||||
google.protobuf.Timestamp create_time = 4 [(google.api.field_behavior) = OUTPUT_ONLY];
|
||||
|
||||
// The type of the notification.
|
||||
Type type = 5 [(google.api.field_behavior) = OUTPUT_ONLY];
|
||||
|
||||
// The activity ID associated with this notification.
|
||||
optional int32 activity_id = 6 [(google.api.field_behavior) = OPTIONAL];
|
||||
|
||||
enum Status {
|
||||
STATUS_UNSPECIFIED = 0;
|
||||
UNREAD = 1;
|
||||
ARCHIVED = 2;
|
||||
}
|
||||
|
||||
enum Type {
|
||||
TYPE_UNSPECIFIED = 0;
|
||||
MEMO_COMMENT = 1;
|
||||
}
|
||||
}
|
||||
|
||||
message ListUserNotificationsRequest {
|
||||
// The parent user resource.
|
||||
// Format: users/{user}
|
||||
string parent = 1 [
|
||||
(google.api.field_behavior) = REQUIRED,
|
||||
(google.api.resource_reference) = {type: "memos.api.v1/User"}
|
||||
];
|
||||
|
||||
int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];
|
||||
string page_token = 3 [(google.api.field_behavior) = OPTIONAL];
|
||||
string filter = 4 [(google.api.field_behavior) = OPTIONAL];
|
||||
}
|
||||
|
||||
message ListUserNotificationsResponse {
|
||||
repeated UserNotification notifications = 1;
|
||||
string next_page_token = 2;
|
||||
}
|
||||
|
||||
message UpdateUserNotificationRequest {
|
||||
UserNotification notification = 1 [(google.api.field_behavior) = REQUIRED];
|
||||
google.protobuf.FieldMask update_mask = 2 [(google.api.field_behavior) = REQUIRED];
|
||||
}
|
||||
|
||||
message DeleteUserNotificationRequest {
|
||||
// Format: users/{user}/notifications/{notification}
|
||||
string name = 1 [
|
||||
(google.api.field_behavior) = REQUIRED,
|
||||
(google.api.resource_reference) = {type: "memos.api.v1/UserNotification"}
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,8 +31,6 @@ const (
|
|||
Activity_TYPE_UNSPECIFIED Activity_Type = 0
|
||||
// Memo comment activity.
|
||||
Activity_MEMO_COMMENT Activity_Type = 1
|
||||
// Version update activity.
|
||||
Activity_VERSION_UPDATE Activity_Type = 2
|
||||
)
|
||||
|
||||
// Enum value maps for Activity_Type.
|
||||
|
|
@ -40,12 +38,10 @@ var (
|
|||
Activity_Type_name = map[int32]string{
|
||||
0: "TYPE_UNSPECIFIED",
|
||||
1: "MEMO_COMMENT",
|
||||
2: "VERSION_UPDATE",
|
||||
}
|
||||
Activity_Type_value = map[string]int32{
|
||||
"TYPE_UNSPECIFIED": 0,
|
||||
"MEMO_COMMENT": 1,
|
||||
"VERSION_UPDATE": 2,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -513,7 +509,7 @@ var File_api_v1_activity_service_proto protoreflect.FileDescriptor
|
|||
|
||||
const file_api_v1_activity_service_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x1dapi/v1/activity_service.proto\x12\fmemos.api.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x17google/api/client.proto\x1a\x1fgoogle/api/field_behavior.proto\x1a\x19google/api/resource.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x86\x04\n" +
|
||||
"\x1dapi/v1/activity_service.proto\x12\fmemos.api.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x17google/api/client.proto\x1a\x1fgoogle/api/field_behavior.proto\x1a\x19google/api/resource.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xf2\x03\n" +
|
||||
"\bActivity\x12\x1a\n" +
|
||||
"\x04name\x18\x01 \x01(\tB\x06\xe0A\x03\xe0A\bR\x04name\x12\x1d\n" +
|
||||
"\acreator\x18\x02 \x01(\tB\x03\xe0A\x03R\acreator\x124\n" +
|
||||
|
|
@ -521,11 +517,10 @@ const file_api_v1_activity_service_proto_rawDesc = "" +
|
|||
"\x05level\x18\x04 \x01(\x0e2\x1c.memos.api.v1.Activity.LevelB\x03\xe0A\x03R\x05level\x12@\n" +
|
||||
"\vcreate_time\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampB\x03\xe0A\x03R\n" +
|
||||
"createTime\x12<\n" +
|
||||
"\apayload\x18\x06 \x01(\v2\x1d.memos.api.v1.ActivityPayloadB\x03\xe0A\x03R\apayload\"B\n" +
|
||||
"\apayload\x18\x06 \x01(\v2\x1d.memos.api.v1.ActivityPayloadB\x03\xe0A\x03R\apayload\".\n" +
|
||||
"\x04Type\x12\x14\n" +
|
||||
"\x10TYPE_UNSPECIFIED\x10\x00\x12\x10\n" +
|
||||
"\fMEMO_COMMENT\x10\x01\x12\x12\n" +
|
||||
"\x0eVERSION_UPDATE\x10\x02\"=\n" +
|
||||
"\fMEMO_COMMENT\x10\x01\"=\n" +
|
||||
"\x05Level\x12\x15\n" +
|
||||
"\x11LEVEL_UNSPECIFIED\x10\x00\x12\b\n" +
|
||||
"\x04INFO\x10\x01\x12\b\n" +
|
||||
|
|
|
|||
|
|
@ -86,8 +86,6 @@ const (
|
|||
Inbox_TYPE_UNSPECIFIED Inbox_Type = 0
|
||||
// Memo comment notification.
|
||||
Inbox_MEMO_COMMENT Inbox_Type = 1
|
||||
// Version update notification.
|
||||
Inbox_VERSION_UPDATE Inbox_Type = 2
|
||||
)
|
||||
|
||||
// Enum value maps for Inbox_Type.
|
||||
|
|
@ -95,12 +93,10 @@ var (
|
|||
Inbox_Type_name = map[int32]string{
|
||||
0: "TYPE_UNSPECIFIED",
|
||||
1: "MEMO_COMMENT",
|
||||
2: "VERSION_UPDATE",
|
||||
}
|
||||
Inbox_Type_value = map[string]int32{
|
||||
"TYPE_UNSPECIFIED": 0,
|
||||
"MEMO_COMMENT": 1,
|
||||
"VERSION_UPDATE": 2,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -500,7 +496,7 @@ var File_api_v1_inbox_service_proto protoreflect.FileDescriptor
|
|||
|
||||
const file_api_v1_inbox_service_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x1aapi/v1/inbox_service.proto\x12\fmemos.api.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x17google/api/client.proto\x1a\x1fgoogle/api/field_behavior.proto\x1a\x19google/api/resource.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a google/protobuf/field_mask.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x87\x04\n" +
|
||||
"\x1aapi/v1/inbox_service.proto\x12\fmemos.api.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x17google/api/client.proto\x1a\x1fgoogle/api/field_behavior.proto\x1a\x19google/api/resource.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a google/protobuf/field_mask.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xf3\x03\n" +
|
||||
"\x05Inbox\x12\x17\n" +
|
||||
"\x04name\x18\x01 \x01(\tB\x03\xe0A\bR\x04name\x12\x1b\n" +
|
||||
"\x06sender\x18\x02 \x01(\tB\x03\xe0A\x03R\x06sender\x12\x1f\n" +
|
||||
|
|
@ -515,11 +511,10 @@ const file_api_v1_inbox_service_proto_rawDesc = "" +
|
|||
"\x12STATUS_UNSPECIFIED\x10\x00\x12\n" +
|
||||
"\n" +
|
||||
"\x06UNREAD\x10\x01\x12\f\n" +
|
||||
"\bARCHIVED\x10\x02\"B\n" +
|
||||
"\bARCHIVED\x10\x02\".\n" +
|
||||
"\x04Type\x12\x14\n" +
|
||||
"\x10TYPE_UNSPECIFIED\x10\x00\x12\x10\n" +
|
||||
"\fMEMO_COMMENT\x10\x01\x12\x12\n" +
|
||||
"\x0eVERSION_UPDATE\x10\x02:>\xeaA;\n" +
|
||||
"\fMEMO_COMMENT\x10\x01:>\xeaA;\n" +
|
||||
"\x12memos.api.v1/Inbox\x12\x0finboxes/{inbox}\x1a\x04name*\ainboxes2\x05inboxB\x0e\n" +
|
||||
"\f_activity_id\"\xca\x01\n" +
|
||||
"\x12ListInboxesRequest\x121\n" +
|
||||
|
|
|
|||
|
|
@ -143,6 +143,101 @@ func (UserSetting_Key) EnumDescriptor() ([]byte, []int) {
|
|||
return file_api_v1_user_service_proto_rawDescGZIP(), []int{12, 0}
|
||||
}
|
||||
|
||||
type UserNotification_Status int32
|
||||
|
||||
const (
|
||||
UserNotification_STATUS_UNSPECIFIED UserNotification_Status = 0
|
||||
UserNotification_UNREAD UserNotification_Status = 1
|
||||
UserNotification_ARCHIVED UserNotification_Status = 2
|
||||
)
|
||||
|
||||
// Enum value maps for UserNotification_Status.
|
||||
var (
|
||||
UserNotification_Status_name = map[int32]string{
|
||||
0: "STATUS_UNSPECIFIED",
|
||||
1: "UNREAD",
|
||||
2: "ARCHIVED",
|
||||
}
|
||||
UserNotification_Status_value = map[string]int32{
|
||||
"STATUS_UNSPECIFIED": 0,
|
||||
"UNREAD": 1,
|
||||
"ARCHIVED": 2,
|
||||
}
|
||||
)
|
||||
|
||||
func (x UserNotification_Status) Enum() *UserNotification_Status {
|
||||
p := new(UserNotification_Status)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x UserNotification_Status) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (UserNotification_Status) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_api_v1_user_service_proto_enumTypes[2].Descriptor()
|
||||
}
|
||||
|
||||
func (UserNotification_Status) Type() protoreflect.EnumType {
|
||||
return &file_api_v1_user_service_proto_enumTypes[2]
|
||||
}
|
||||
|
||||
func (x UserNotification_Status) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use UserNotification_Status.Descriptor instead.
|
||||
func (UserNotification_Status) EnumDescriptor() ([]byte, []int) {
|
||||
return file_api_v1_user_service_proto_rawDescGZIP(), []int{32, 0}
|
||||
}
|
||||
|
||||
type UserNotification_Type int32
|
||||
|
||||
const (
|
||||
UserNotification_TYPE_UNSPECIFIED UserNotification_Type = 0
|
||||
UserNotification_MEMO_COMMENT UserNotification_Type = 1
|
||||
)
|
||||
|
||||
// Enum value maps for UserNotification_Type.
|
||||
var (
|
||||
UserNotification_Type_name = map[int32]string{
|
||||
0: "TYPE_UNSPECIFIED",
|
||||
1: "MEMO_COMMENT",
|
||||
}
|
||||
UserNotification_Type_value = map[string]int32{
|
||||
"TYPE_UNSPECIFIED": 0,
|
||||
"MEMO_COMMENT": 1,
|
||||
}
|
||||
)
|
||||
|
||||
func (x UserNotification_Type) Enum() *UserNotification_Type {
|
||||
p := new(UserNotification_Type)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x UserNotification_Type) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (UserNotification_Type) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_api_v1_user_service_proto_enumTypes[3].Descriptor()
|
||||
}
|
||||
|
||||
func (UserNotification_Type) Type() protoreflect.EnumType {
|
||||
return &file_api_v1_user_service_proto_enumTypes[3]
|
||||
}
|
||||
|
||||
func (x UserNotification_Type) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use UserNotification_Type.Descriptor instead.
|
||||
func (UserNotification_Type) EnumDescriptor() ([]byte, []int) {
|
||||
return file_api_v1_user_service_proto_rawDescGZIP(), []int{32, 1}
|
||||
}
|
||||
|
||||
type User struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// The resource name of the user.
|
||||
|
|
@ -2169,6 +2264,317 @@ func (x *DeleteUserWebhookRequest) GetName() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
type UserNotification struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// The resource name of the notification.
|
||||
// Format: users/{user}/notifications/{notification}
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
// The sender of the notification.
|
||||
// Format: users/{user}
|
||||
Sender string `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"`
|
||||
// The status of the notification.
|
||||
Status UserNotification_Status `protobuf:"varint,3,opt,name=status,proto3,enum=memos.api.v1.UserNotification_Status" json:"status,omitempty"`
|
||||
// The creation timestamp.
|
||||
CreateTime *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty"`
|
||||
// The type of the notification.
|
||||
Type UserNotification_Type `protobuf:"varint,5,opt,name=type,proto3,enum=memos.api.v1.UserNotification_Type" json:"type,omitempty"`
|
||||
// The activity ID associated with this notification.
|
||||
ActivityId *int32 `protobuf:"varint,6,opt,name=activity_id,json=activityId,proto3,oneof" json:"activity_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *UserNotification) Reset() {
|
||||
*x = UserNotification{}
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[32]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *UserNotification) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UserNotification) ProtoMessage() {}
|
||||
|
||||
func (x *UserNotification) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[32]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use UserNotification.ProtoReflect.Descriptor instead.
|
||||
func (*UserNotification) Descriptor() ([]byte, []int) {
|
||||
return file_api_v1_user_service_proto_rawDescGZIP(), []int{32}
|
||||
}
|
||||
|
||||
func (x *UserNotification) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *UserNotification) GetSender() string {
|
||||
if x != nil {
|
||||
return x.Sender
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *UserNotification) GetStatus() UserNotification_Status {
|
||||
if x != nil {
|
||||
return x.Status
|
||||
}
|
||||
return UserNotification_STATUS_UNSPECIFIED
|
||||
}
|
||||
|
||||
func (x *UserNotification) GetCreateTime() *timestamppb.Timestamp {
|
||||
if x != nil {
|
||||
return x.CreateTime
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UserNotification) GetType() UserNotification_Type {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return UserNotification_TYPE_UNSPECIFIED
|
||||
}
|
||||
|
||||
func (x *UserNotification) GetActivityId() int32 {
|
||||
if x != nil && x.ActivityId != nil {
|
||||
return *x.ActivityId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type ListUserNotificationsRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// The parent user resource.
|
||||
// Format: users/{user}
|
||||
Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"`
|
||||
PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
|
||||
PageToken string `protobuf:"bytes,3,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"`
|
||||
Filter string `protobuf:"bytes,4,opt,name=filter,proto3" json:"filter,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ListUserNotificationsRequest) Reset() {
|
||||
*x = ListUserNotificationsRequest{}
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[33]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListUserNotificationsRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListUserNotificationsRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ListUserNotificationsRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[33]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListUserNotificationsRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ListUserNotificationsRequest) Descriptor() ([]byte, []int) {
|
||||
return file_api_v1_user_service_proto_rawDescGZIP(), []int{33}
|
||||
}
|
||||
|
||||
func (x *ListUserNotificationsRequest) GetParent() string {
|
||||
if x != nil {
|
||||
return x.Parent
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ListUserNotificationsRequest) GetPageSize() int32 {
|
||||
if x != nil {
|
||||
return x.PageSize
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ListUserNotificationsRequest) GetPageToken() string {
|
||||
if x != nil {
|
||||
return x.PageToken
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ListUserNotificationsRequest) GetFilter() string {
|
||||
if x != nil {
|
||||
return x.Filter
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ListUserNotificationsResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Notifications []*UserNotification `protobuf:"bytes,1,rep,name=notifications,proto3" json:"notifications,omitempty"`
|
||||
NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ListUserNotificationsResponse) Reset() {
|
||||
*x = ListUserNotificationsResponse{}
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[34]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListUserNotificationsResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListUserNotificationsResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ListUserNotificationsResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[34]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListUserNotificationsResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ListUserNotificationsResponse) Descriptor() ([]byte, []int) {
|
||||
return file_api_v1_user_service_proto_rawDescGZIP(), []int{34}
|
||||
}
|
||||
|
||||
func (x *ListUserNotificationsResponse) GetNotifications() []*UserNotification {
|
||||
if x != nil {
|
||||
return x.Notifications
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ListUserNotificationsResponse) GetNextPageToken() string {
|
||||
if x != nil {
|
||||
return x.NextPageToken
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type UpdateUserNotificationRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Notification *UserNotification `protobuf:"bytes,1,opt,name=notification,proto3" json:"notification,omitempty"`
|
||||
UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *UpdateUserNotificationRequest) Reset() {
|
||||
*x = UpdateUserNotificationRequest{}
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[35]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *UpdateUserNotificationRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UpdateUserNotificationRequest) ProtoMessage() {}
|
||||
|
||||
func (x *UpdateUserNotificationRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[35]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use UpdateUserNotificationRequest.ProtoReflect.Descriptor instead.
|
||||
func (*UpdateUserNotificationRequest) Descriptor() ([]byte, []int) {
|
||||
return file_api_v1_user_service_proto_rawDescGZIP(), []int{35}
|
||||
}
|
||||
|
||||
func (x *UpdateUserNotificationRequest) GetNotification() *UserNotification {
|
||||
if x != nil {
|
||||
return x.Notification
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UpdateUserNotificationRequest) GetUpdateMask() *fieldmaskpb.FieldMask {
|
||||
if x != nil {
|
||||
return x.UpdateMask
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type DeleteUserNotificationRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Format: users/{user}/notifications/{notification}
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *DeleteUserNotificationRequest) Reset() {
|
||||
*x = DeleteUserNotificationRequest{}
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[36]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *DeleteUserNotificationRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DeleteUserNotificationRequest) ProtoMessage() {}
|
||||
|
||||
func (x *DeleteUserNotificationRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[36]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use DeleteUserNotificationRequest.ProtoReflect.Descriptor instead.
|
||||
func (*DeleteUserNotificationRequest) Descriptor() ([]byte, []int) {
|
||||
return file_api_v1_user_service_proto_rawDescGZIP(), []int{36}
|
||||
}
|
||||
|
||||
func (x *DeleteUserNotificationRequest) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Memo type statistics.
|
||||
type UserStats_MemoTypeStats struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
|
|
@ -2182,7 +2588,7 @@ type UserStats_MemoTypeStats struct {
|
|||
|
||||
func (x *UserStats_MemoTypeStats) Reset() {
|
||||
*x = UserStats_MemoTypeStats{}
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[33]
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[38]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
|
@ -2194,7 +2600,7 @@ func (x *UserStats_MemoTypeStats) String() string {
|
|||
func (*UserStats_MemoTypeStats) ProtoMessage() {}
|
||||
|
||||
func (x *UserStats_MemoTypeStats) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[33]
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[38]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
|
|
@ -2255,7 +2661,7 @@ type UserSetting_GeneralSetting struct {
|
|||
|
||||
func (x *UserSetting_GeneralSetting) Reset() {
|
||||
*x = UserSetting_GeneralSetting{}
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[34]
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[39]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
|
@ -2267,7 +2673,7 @@ func (x *UserSetting_GeneralSetting) String() string {
|
|||
func (*UserSetting_GeneralSetting) ProtoMessage() {}
|
||||
|
||||
func (x *UserSetting_GeneralSetting) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[34]
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[39]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
|
|
@ -2315,7 +2721,7 @@ type UserSetting_SessionsSetting struct {
|
|||
|
||||
func (x *UserSetting_SessionsSetting) Reset() {
|
||||
*x = UserSetting_SessionsSetting{}
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[35]
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[40]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
|
@ -2327,7 +2733,7 @@ func (x *UserSetting_SessionsSetting) String() string {
|
|||
func (*UserSetting_SessionsSetting) ProtoMessage() {}
|
||||
|
||||
func (x *UserSetting_SessionsSetting) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[35]
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[40]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
|
|
@ -2361,7 +2767,7 @@ type UserSetting_AccessTokensSetting struct {
|
|||
|
||||
func (x *UserSetting_AccessTokensSetting) Reset() {
|
||||
*x = UserSetting_AccessTokensSetting{}
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[36]
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[41]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
|
@ -2373,7 +2779,7 @@ func (x *UserSetting_AccessTokensSetting) String() string {
|
|||
func (*UserSetting_AccessTokensSetting) ProtoMessage() {}
|
||||
|
||||
func (x *UserSetting_AccessTokensSetting) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[36]
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[41]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
|
|
@ -2407,7 +2813,7 @@ type UserSetting_WebhooksSetting struct {
|
|||
|
||||
func (x *UserSetting_WebhooksSetting) Reset() {
|
||||
*x = UserSetting_WebhooksSetting{}
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[37]
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[42]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
|
@ -2419,7 +2825,7 @@ func (x *UserSetting_WebhooksSetting) String() string {
|
|||
func (*UserSetting_WebhooksSetting) ProtoMessage() {}
|
||||
|
||||
func (x *UserSetting_WebhooksSetting) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[37]
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[42]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
|
|
@ -2460,7 +2866,7 @@ type UserSession_ClientInfo struct {
|
|||
|
||||
func (x *UserSession_ClientInfo) Reset() {
|
||||
*x = UserSession_ClientInfo{}
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[38]
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[43]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
|
@ -2472,7 +2878,7 @@ func (x *UserSession_ClientInfo) String() string {
|
|||
func (*UserSession_ClientInfo) ProtoMessage() {}
|
||||
|
||||
func (x *UserSession_ClientInfo) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[38]
|
||||
mi := &file_api_v1_user_service_proto_msgTypes[43]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
|
|
@ -2725,7 +3131,44 @@ const file_api_v1_user_service_proto_rawDesc = "" +
|
|||
"\vupdate_mask\x18\x02 \x01(\v2\x1a.google.protobuf.FieldMaskR\n" +
|
||||
"updateMask\"3\n" +
|
||||
"\x18DeleteUserWebhookRequest\x12\x17\n" +
|
||||
"\x04name\x18\x01 \x01(\tB\x03\xe0A\x02R\x04name2\xe6\x15\n" +
|
||||
"\x04name\x18\x01 \x01(\tB\x03\xe0A\x02R\x04name\"\xbe\x04\n" +
|
||||
"\x10UserNotification\x12\x1a\n" +
|
||||
"\x04name\x18\x01 \x01(\tB\x06\xe0A\x03\xe0A\bR\x04name\x121\n" +
|
||||
"\x06sender\x18\x02 \x01(\tB\x19\xe0A\x03\xfaA\x13\n" +
|
||||
"\x11memos.api.v1/UserR\x06sender\x12B\n" +
|
||||
"\x06status\x18\x03 \x01(\x0e2%.memos.api.v1.UserNotification.StatusB\x03\xe0A\x01R\x06status\x12@\n" +
|
||||
"\vcreate_time\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampB\x03\xe0A\x03R\n" +
|
||||
"createTime\x12<\n" +
|
||||
"\x04type\x18\x05 \x01(\x0e2#.memos.api.v1.UserNotification.TypeB\x03\xe0A\x03R\x04type\x12)\n" +
|
||||
"\vactivity_id\x18\x06 \x01(\x05B\x03\xe0A\x01H\x00R\n" +
|
||||
"activityId\x88\x01\x01\":\n" +
|
||||
"\x06Status\x12\x16\n" +
|
||||
"\x12STATUS_UNSPECIFIED\x10\x00\x12\n" +
|
||||
"\n" +
|
||||
"\x06UNREAD\x10\x01\x12\f\n" +
|
||||
"\bARCHIVED\x10\x02\".\n" +
|
||||
"\x04Type\x12\x14\n" +
|
||||
"\x10TYPE_UNSPECIFIED\x10\x00\x12\x10\n" +
|
||||
"\fMEMO_COMMENT\x10\x01:p\xeaAm\n" +
|
||||
"\x1dmemos.api.v1/UserNotification\x12)users/{user}/notifications/{notification}\x1a\x04name*\rnotifications2\fnotificationB\x0e\n" +
|
||||
"\f_activity_id\"\xb4\x01\n" +
|
||||
"\x1cListUserNotificationsRequest\x121\n" +
|
||||
"\x06parent\x18\x01 \x01(\tB\x19\xe0A\x02\xfaA\x13\n" +
|
||||
"\x11memos.api.v1/UserR\x06parent\x12 \n" +
|
||||
"\tpage_size\x18\x02 \x01(\x05B\x03\xe0A\x01R\bpageSize\x12\"\n" +
|
||||
"\n" +
|
||||
"page_token\x18\x03 \x01(\tB\x03\xe0A\x01R\tpageToken\x12\x1b\n" +
|
||||
"\x06filter\x18\x04 \x01(\tB\x03\xe0A\x01R\x06filter\"\x8d\x01\n" +
|
||||
"\x1dListUserNotificationsResponse\x12D\n" +
|
||||
"\rnotifications\x18\x01 \x03(\v2\x1e.memos.api.v1.UserNotificationR\rnotifications\x12&\n" +
|
||||
"\x0fnext_page_token\x18\x02 \x01(\tR\rnextPageToken\"\xaa\x01\n" +
|
||||
"\x1dUpdateUserNotificationRequest\x12G\n" +
|
||||
"\fnotification\x18\x01 \x01(\v2\x1e.memos.api.v1.UserNotificationB\x03\xe0A\x02R\fnotification\x12@\n" +
|
||||
"\vupdate_mask\x18\x02 \x01(\v2\x1a.google.protobuf.FieldMaskB\x03\xe0A\x02R\n" +
|
||||
"updateMask\"Z\n" +
|
||||
"\x1dDeleteUserNotificationRequest\x129\n" +
|
||||
"\x04name\x18\x01 \x01(\tB%\xe0A\x02\xfaA\x1f\n" +
|
||||
"\x1dmemos.api.v1/UserNotificationR\x04name2\xf7\x19\n" +
|
||||
"\vUserService\x12c\n" +
|
||||
"\tListUsers\x12\x1e.memos.api.v1.ListUsersRequest\x1a\x1f.memos.api.v1.ListUsersResponse\"\x15\x82\xd3\xe4\x93\x02\x0f\x12\r/api/v1/users\x12b\n" +
|
||||
"\aGetUser\x12\x1c.memos.api.v1.GetUserRequest\x1a\x12.memos.api.v1.User\"%\xdaA\x04name\x82\xd3\xe4\x93\x02\x18\x12\x16/api/v1/{name=users/*}\x12e\n" +
|
||||
|
|
@ -2749,7 +3192,10 @@ const file_api_v1_user_service_proto_rawDesc = "" +
|
|||
"\x10ListUserWebhooks\x12%.memos.api.v1.ListUserWebhooksRequest\x1a&.memos.api.v1.ListUserWebhooksResponse\"2\xdaA\x06parent\x82\xd3\xe4\x93\x02#\x12!/api/v1/{parent=users/*}/webhooks\x12\x9b\x01\n" +
|
||||
"\x11CreateUserWebhook\x12&.memos.api.v1.CreateUserWebhookRequest\x1a\x19.memos.api.v1.UserWebhook\"C\xdaA\x0eparent,webhook\x82\xd3\xe4\x93\x02,:\awebhook\"!/api/v1/{parent=users/*}/webhooks\x12\xa8\x01\n" +
|
||||
"\x11UpdateUserWebhook\x12&.memos.api.v1.UpdateUserWebhookRequest\x1a\x19.memos.api.v1.UserWebhook\"P\xdaA\x13webhook,update_mask\x82\xd3\xe4\x93\x024:\awebhook2)/api/v1/{webhook.name=users/*/webhooks/*}\x12\x85\x01\n" +
|
||||
"\x11DeleteUserWebhook\x12&.memos.api.v1.DeleteUserWebhookRequest\x1a\x16.google.protobuf.Empty\"0\xdaA\x04name\x82\xd3\xe4\x93\x02#*!/api/v1/{name=users/*/webhooks/*}B\xa8\x01\n" +
|
||||
"\x11DeleteUserWebhook\x12&.memos.api.v1.DeleteUserWebhookRequest\x1a\x16.google.protobuf.Empty\"0\xdaA\x04name\x82\xd3\xe4\x93\x02#*!/api/v1/{name=users/*/webhooks/*}\x12\xa9\x01\n" +
|
||||
"\x15ListUserNotifications\x12*.memos.api.v1.ListUserNotificationsRequest\x1a+.memos.api.v1.ListUserNotificationsResponse\"7\xdaA\x06parent\x82\xd3\xe4\x93\x02(\x12&/api/v1/{parent=users/*}/notifications\x12\xcb\x01\n" +
|
||||
"\x16UpdateUserNotification\x12+.memos.api.v1.UpdateUserNotificationRequest\x1a\x1e.memos.api.v1.UserNotification\"d\xdaA\x18notification,update_mask\x82\xd3\xe4\x93\x02C:\fnotification23/api/v1/{notification.name=users/*/notifications/*}\x12\x94\x01\n" +
|
||||
"\x16DeleteUserNotification\x12+.memos.api.v1.DeleteUserNotificationRequest\x1a\x16.google.protobuf.Empty\"5\xdaA\x04name\x82\xd3\xe4\x93\x02(*&/api/v1/{name=users/*/notifications/*}B\xa8\x01\n" +
|
||||
"\x10com.memos.api.v1B\x10UserServiceProtoP\x01Z0github.com/usememos/memos/proto/gen/api/v1;apiv1\xa2\x02\x03MAX\xaa\x02\fMemos.Api.V1\xca\x02\fMemos\\Api\\V1\xe2\x02\x18Memos\\Api\\V1\\GPBMetadata\xea\x02\x0eMemos::Api::V1b\x06proto3"
|
||||
|
||||
var (
|
||||
|
|
@ -2764,139 +3210,158 @@ func file_api_v1_user_service_proto_rawDescGZIP() []byte {
|
|||
return file_api_v1_user_service_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_api_v1_user_service_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||
var file_api_v1_user_service_proto_msgTypes = make([]protoimpl.MessageInfo, 39)
|
||||
var file_api_v1_user_service_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
|
||||
var file_api_v1_user_service_proto_msgTypes = make([]protoimpl.MessageInfo, 44)
|
||||
var file_api_v1_user_service_proto_goTypes = []any{
|
||||
(User_Role)(0), // 0: memos.api.v1.User.Role
|
||||
(UserSetting_Key)(0), // 1: memos.api.v1.UserSetting.Key
|
||||
(*User)(nil), // 2: memos.api.v1.User
|
||||
(*ListUsersRequest)(nil), // 3: memos.api.v1.ListUsersRequest
|
||||
(*ListUsersResponse)(nil), // 4: memos.api.v1.ListUsersResponse
|
||||
(*GetUserRequest)(nil), // 5: memos.api.v1.GetUserRequest
|
||||
(*CreateUserRequest)(nil), // 6: memos.api.v1.CreateUserRequest
|
||||
(*UpdateUserRequest)(nil), // 7: memos.api.v1.UpdateUserRequest
|
||||
(*DeleteUserRequest)(nil), // 8: memos.api.v1.DeleteUserRequest
|
||||
(*GetUserAvatarRequest)(nil), // 9: memos.api.v1.GetUserAvatarRequest
|
||||
(*UserStats)(nil), // 10: memos.api.v1.UserStats
|
||||
(*GetUserStatsRequest)(nil), // 11: memos.api.v1.GetUserStatsRequest
|
||||
(*ListAllUserStatsRequest)(nil), // 12: memos.api.v1.ListAllUserStatsRequest
|
||||
(*ListAllUserStatsResponse)(nil), // 13: memos.api.v1.ListAllUserStatsResponse
|
||||
(*UserSetting)(nil), // 14: memos.api.v1.UserSetting
|
||||
(*GetUserSettingRequest)(nil), // 15: memos.api.v1.GetUserSettingRequest
|
||||
(*UpdateUserSettingRequest)(nil), // 16: memos.api.v1.UpdateUserSettingRequest
|
||||
(*ListUserSettingsRequest)(nil), // 17: memos.api.v1.ListUserSettingsRequest
|
||||
(*ListUserSettingsResponse)(nil), // 18: memos.api.v1.ListUserSettingsResponse
|
||||
(*UserAccessToken)(nil), // 19: memos.api.v1.UserAccessToken
|
||||
(*ListUserAccessTokensRequest)(nil), // 20: memos.api.v1.ListUserAccessTokensRequest
|
||||
(*ListUserAccessTokensResponse)(nil), // 21: memos.api.v1.ListUserAccessTokensResponse
|
||||
(*CreateUserAccessTokenRequest)(nil), // 22: memos.api.v1.CreateUserAccessTokenRequest
|
||||
(*DeleteUserAccessTokenRequest)(nil), // 23: memos.api.v1.DeleteUserAccessTokenRequest
|
||||
(*UserSession)(nil), // 24: memos.api.v1.UserSession
|
||||
(*ListUserSessionsRequest)(nil), // 25: memos.api.v1.ListUserSessionsRequest
|
||||
(*ListUserSessionsResponse)(nil), // 26: memos.api.v1.ListUserSessionsResponse
|
||||
(*RevokeUserSessionRequest)(nil), // 27: memos.api.v1.RevokeUserSessionRequest
|
||||
(*UserWebhook)(nil), // 28: memos.api.v1.UserWebhook
|
||||
(*ListUserWebhooksRequest)(nil), // 29: memos.api.v1.ListUserWebhooksRequest
|
||||
(*ListUserWebhooksResponse)(nil), // 30: memos.api.v1.ListUserWebhooksResponse
|
||||
(*CreateUserWebhookRequest)(nil), // 31: memos.api.v1.CreateUserWebhookRequest
|
||||
(*UpdateUserWebhookRequest)(nil), // 32: memos.api.v1.UpdateUserWebhookRequest
|
||||
(*DeleteUserWebhookRequest)(nil), // 33: memos.api.v1.DeleteUserWebhookRequest
|
||||
nil, // 34: memos.api.v1.UserStats.TagCountEntry
|
||||
(*UserStats_MemoTypeStats)(nil), // 35: memos.api.v1.UserStats.MemoTypeStats
|
||||
(*UserSetting_GeneralSetting)(nil), // 36: memos.api.v1.UserSetting.GeneralSetting
|
||||
(*UserSetting_SessionsSetting)(nil), // 37: memos.api.v1.UserSetting.SessionsSetting
|
||||
(*UserSetting_AccessTokensSetting)(nil), // 38: memos.api.v1.UserSetting.AccessTokensSetting
|
||||
(*UserSetting_WebhooksSetting)(nil), // 39: memos.api.v1.UserSetting.WebhooksSetting
|
||||
(*UserSession_ClientInfo)(nil), // 40: memos.api.v1.UserSession.ClientInfo
|
||||
(State)(0), // 41: memos.api.v1.State
|
||||
(*timestamppb.Timestamp)(nil), // 42: google.protobuf.Timestamp
|
||||
(*fieldmaskpb.FieldMask)(nil), // 43: google.protobuf.FieldMask
|
||||
(*emptypb.Empty)(nil), // 44: google.protobuf.Empty
|
||||
(*httpbody.HttpBody)(nil), // 45: google.api.HttpBody
|
||||
(UserNotification_Status)(0), // 2: memos.api.v1.UserNotification.Status
|
||||
(UserNotification_Type)(0), // 3: memos.api.v1.UserNotification.Type
|
||||
(*User)(nil), // 4: memos.api.v1.User
|
||||
(*ListUsersRequest)(nil), // 5: memos.api.v1.ListUsersRequest
|
||||
(*ListUsersResponse)(nil), // 6: memos.api.v1.ListUsersResponse
|
||||
(*GetUserRequest)(nil), // 7: memos.api.v1.GetUserRequest
|
||||
(*CreateUserRequest)(nil), // 8: memos.api.v1.CreateUserRequest
|
||||
(*UpdateUserRequest)(nil), // 9: memos.api.v1.UpdateUserRequest
|
||||
(*DeleteUserRequest)(nil), // 10: memos.api.v1.DeleteUserRequest
|
||||
(*GetUserAvatarRequest)(nil), // 11: memos.api.v1.GetUserAvatarRequest
|
||||
(*UserStats)(nil), // 12: memos.api.v1.UserStats
|
||||
(*GetUserStatsRequest)(nil), // 13: memos.api.v1.GetUserStatsRequest
|
||||
(*ListAllUserStatsRequest)(nil), // 14: memos.api.v1.ListAllUserStatsRequest
|
||||
(*ListAllUserStatsResponse)(nil), // 15: memos.api.v1.ListAllUserStatsResponse
|
||||
(*UserSetting)(nil), // 16: memos.api.v1.UserSetting
|
||||
(*GetUserSettingRequest)(nil), // 17: memos.api.v1.GetUserSettingRequest
|
||||
(*UpdateUserSettingRequest)(nil), // 18: memos.api.v1.UpdateUserSettingRequest
|
||||
(*ListUserSettingsRequest)(nil), // 19: memos.api.v1.ListUserSettingsRequest
|
||||
(*ListUserSettingsResponse)(nil), // 20: memos.api.v1.ListUserSettingsResponse
|
||||
(*UserAccessToken)(nil), // 21: memos.api.v1.UserAccessToken
|
||||
(*ListUserAccessTokensRequest)(nil), // 22: memos.api.v1.ListUserAccessTokensRequest
|
||||
(*ListUserAccessTokensResponse)(nil), // 23: memos.api.v1.ListUserAccessTokensResponse
|
||||
(*CreateUserAccessTokenRequest)(nil), // 24: memos.api.v1.CreateUserAccessTokenRequest
|
||||
(*DeleteUserAccessTokenRequest)(nil), // 25: memos.api.v1.DeleteUserAccessTokenRequest
|
||||
(*UserSession)(nil), // 26: memos.api.v1.UserSession
|
||||
(*ListUserSessionsRequest)(nil), // 27: memos.api.v1.ListUserSessionsRequest
|
||||
(*ListUserSessionsResponse)(nil), // 28: memos.api.v1.ListUserSessionsResponse
|
||||
(*RevokeUserSessionRequest)(nil), // 29: memos.api.v1.RevokeUserSessionRequest
|
||||
(*UserWebhook)(nil), // 30: memos.api.v1.UserWebhook
|
||||
(*ListUserWebhooksRequest)(nil), // 31: memos.api.v1.ListUserWebhooksRequest
|
||||
(*ListUserWebhooksResponse)(nil), // 32: memos.api.v1.ListUserWebhooksResponse
|
||||
(*CreateUserWebhookRequest)(nil), // 33: memos.api.v1.CreateUserWebhookRequest
|
||||
(*UpdateUserWebhookRequest)(nil), // 34: memos.api.v1.UpdateUserWebhookRequest
|
||||
(*DeleteUserWebhookRequest)(nil), // 35: memos.api.v1.DeleteUserWebhookRequest
|
||||
(*UserNotification)(nil), // 36: memos.api.v1.UserNotification
|
||||
(*ListUserNotificationsRequest)(nil), // 37: memos.api.v1.ListUserNotificationsRequest
|
||||
(*ListUserNotificationsResponse)(nil), // 38: memos.api.v1.ListUserNotificationsResponse
|
||||
(*UpdateUserNotificationRequest)(nil), // 39: memos.api.v1.UpdateUserNotificationRequest
|
||||
(*DeleteUserNotificationRequest)(nil), // 40: memos.api.v1.DeleteUserNotificationRequest
|
||||
nil, // 41: memos.api.v1.UserStats.TagCountEntry
|
||||
(*UserStats_MemoTypeStats)(nil), // 42: memos.api.v1.UserStats.MemoTypeStats
|
||||
(*UserSetting_GeneralSetting)(nil), // 43: memos.api.v1.UserSetting.GeneralSetting
|
||||
(*UserSetting_SessionsSetting)(nil), // 44: memos.api.v1.UserSetting.SessionsSetting
|
||||
(*UserSetting_AccessTokensSetting)(nil), // 45: memos.api.v1.UserSetting.AccessTokensSetting
|
||||
(*UserSetting_WebhooksSetting)(nil), // 46: memos.api.v1.UserSetting.WebhooksSetting
|
||||
(*UserSession_ClientInfo)(nil), // 47: memos.api.v1.UserSession.ClientInfo
|
||||
(State)(0), // 48: memos.api.v1.State
|
||||
(*timestamppb.Timestamp)(nil), // 49: google.protobuf.Timestamp
|
||||
(*fieldmaskpb.FieldMask)(nil), // 50: google.protobuf.FieldMask
|
||||
(*emptypb.Empty)(nil), // 51: google.protobuf.Empty
|
||||
(*httpbody.HttpBody)(nil), // 52: google.api.HttpBody
|
||||
}
|
||||
var file_api_v1_user_service_proto_depIdxs = []int32{
|
||||
0, // 0: memos.api.v1.User.role:type_name -> memos.api.v1.User.Role
|
||||
41, // 1: memos.api.v1.User.state:type_name -> memos.api.v1.State
|
||||
42, // 2: memos.api.v1.User.create_time:type_name -> google.protobuf.Timestamp
|
||||
42, // 3: memos.api.v1.User.update_time:type_name -> google.protobuf.Timestamp
|
||||
2, // 4: memos.api.v1.ListUsersResponse.users:type_name -> memos.api.v1.User
|
||||
43, // 5: memos.api.v1.GetUserRequest.read_mask:type_name -> google.protobuf.FieldMask
|
||||
2, // 6: memos.api.v1.CreateUserRequest.user:type_name -> memos.api.v1.User
|
||||
2, // 7: memos.api.v1.UpdateUserRequest.user:type_name -> memos.api.v1.User
|
||||
43, // 8: memos.api.v1.UpdateUserRequest.update_mask:type_name -> google.protobuf.FieldMask
|
||||
42, // 9: memos.api.v1.UserStats.memo_display_timestamps:type_name -> google.protobuf.Timestamp
|
||||
35, // 10: memos.api.v1.UserStats.memo_type_stats:type_name -> memos.api.v1.UserStats.MemoTypeStats
|
||||
34, // 11: memos.api.v1.UserStats.tag_count:type_name -> memos.api.v1.UserStats.TagCountEntry
|
||||
10, // 12: memos.api.v1.ListAllUserStatsResponse.stats:type_name -> memos.api.v1.UserStats
|
||||
36, // 13: memos.api.v1.UserSetting.general_setting:type_name -> memos.api.v1.UserSetting.GeneralSetting
|
||||
37, // 14: memos.api.v1.UserSetting.sessions_setting:type_name -> memos.api.v1.UserSetting.SessionsSetting
|
||||
38, // 15: memos.api.v1.UserSetting.access_tokens_setting:type_name -> memos.api.v1.UserSetting.AccessTokensSetting
|
||||
39, // 16: memos.api.v1.UserSetting.webhooks_setting:type_name -> memos.api.v1.UserSetting.WebhooksSetting
|
||||
14, // 17: memos.api.v1.UpdateUserSettingRequest.setting:type_name -> memos.api.v1.UserSetting
|
||||
43, // 18: memos.api.v1.UpdateUserSettingRequest.update_mask:type_name -> google.protobuf.FieldMask
|
||||
14, // 19: memos.api.v1.ListUserSettingsResponse.settings:type_name -> memos.api.v1.UserSetting
|
||||
42, // 20: memos.api.v1.UserAccessToken.issued_at:type_name -> google.protobuf.Timestamp
|
||||
42, // 21: memos.api.v1.UserAccessToken.expires_at:type_name -> google.protobuf.Timestamp
|
||||
19, // 22: memos.api.v1.ListUserAccessTokensResponse.access_tokens:type_name -> memos.api.v1.UserAccessToken
|
||||
19, // 23: memos.api.v1.CreateUserAccessTokenRequest.access_token:type_name -> memos.api.v1.UserAccessToken
|
||||
42, // 24: memos.api.v1.UserSession.create_time:type_name -> google.protobuf.Timestamp
|
||||
42, // 25: memos.api.v1.UserSession.last_accessed_time:type_name -> google.protobuf.Timestamp
|
||||
40, // 26: memos.api.v1.UserSession.client_info:type_name -> memos.api.v1.UserSession.ClientInfo
|
||||
24, // 27: memos.api.v1.ListUserSessionsResponse.sessions:type_name -> memos.api.v1.UserSession
|
||||
42, // 28: memos.api.v1.UserWebhook.create_time:type_name -> google.protobuf.Timestamp
|
||||
42, // 29: memos.api.v1.UserWebhook.update_time:type_name -> google.protobuf.Timestamp
|
||||
28, // 30: memos.api.v1.ListUserWebhooksResponse.webhooks:type_name -> memos.api.v1.UserWebhook
|
||||
28, // 31: memos.api.v1.CreateUserWebhookRequest.webhook:type_name -> memos.api.v1.UserWebhook
|
||||
28, // 32: memos.api.v1.UpdateUserWebhookRequest.webhook:type_name -> memos.api.v1.UserWebhook
|
||||
43, // 33: memos.api.v1.UpdateUserWebhookRequest.update_mask:type_name -> google.protobuf.FieldMask
|
||||
24, // 34: memos.api.v1.UserSetting.SessionsSetting.sessions:type_name -> memos.api.v1.UserSession
|
||||
19, // 35: memos.api.v1.UserSetting.AccessTokensSetting.access_tokens:type_name -> memos.api.v1.UserAccessToken
|
||||
28, // 36: memos.api.v1.UserSetting.WebhooksSetting.webhooks:type_name -> memos.api.v1.UserWebhook
|
||||
3, // 37: memos.api.v1.UserService.ListUsers:input_type -> memos.api.v1.ListUsersRequest
|
||||
5, // 38: memos.api.v1.UserService.GetUser:input_type -> memos.api.v1.GetUserRequest
|
||||
6, // 39: memos.api.v1.UserService.CreateUser:input_type -> memos.api.v1.CreateUserRequest
|
||||
7, // 40: memos.api.v1.UserService.UpdateUser:input_type -> memos.api.v1.UpdateUserRequest
|
||||
8, // 41: memos.api.v1.UserService.DeleteUser:input_type -> memos.api.v1.DeleteUserRequest
|
||||
9, // 42: memos.api.v1.UserService.GetUserAvatar:input_type -> memos.api.v1.GetUserAvatarRequest
|
||||
12, // 43: memos.api.v1.UserService.ListAllUserStats:input_type -> memos.api.v1.ListAllUserStatsRequest
|
||||
11, // 44: memos.api.v1.UserService.GetUserStats:input_type -> memos.api.v1.GetUserStatsRequest
|
||||
15, // 45: memos.api.v1.UserService.GetUserSetting:input_type -> memos.api.v1.GetUserSettingRequest
|
||||
16, // 46: memos.api.v1.UserService.UpdateUserSetting:input_type -> memos.api.v1.UpdateUserSettingRequest
|
||||
17, // 47: memos.api.v1.UserService.ListUserSettings:input_type -> memos.api.v1.ListUserSettingsRequest
|
||||
20, // 48: memos.api.v1.UserService.ListUserAccessTokens:input_type -> memos.api.v1.ListUserAccessTokensRequest
|
||||
22, // 49: memos.api.v1.UserService.CreateUserAccessToken:input_type -> memos.api.v1.CreateUserAccessTokenRequest
|
||||
23, // 50: memos.api.v1.UserService.DeleteUserAccessToken:input_type -> memos.api.v1.DeleteUserAccessTokenRequest
|
||||
25, // 51: memos.api.v1.UserService.ListUserSessions:input_type -> memos.api.v1.ListUserSessionsRequest
|
||||
27, // 52: memos.api.v1.UserService.RevokeUserSession:input_type -> memos.api.v1.RevokeUserSessionRequest
|
||||
29, // 53: memos.api.v1.UserService.ListUserWebhooks:input_type -> memos.api.v1.ListUserWebhooksRequest
|
||||
31, // 54: memos.api.v1.UserService.CreateUserWebhook:input_type -> memos.api.v1.CreateUserWebhookRequest
|
||||
32, // 55: memos.api.v1.UserService.UpdateUserWebhook:input_type -> memos.api.v1.UpdateUserWebhookRequest
|
||||
33, // 56: memos.api.v1.UserService.DeleteUserWebhook:input_type -> memos.api.v1.DeleteUserWebhookRequest
|
||||
4, // 57: memos.api.v1.UserService.ListUsers:output_type -> memos.api.v1.ListUsersResponse
|
||||
2, // 58: memos.api.v1.UserService.GetUser:output_type -> memos.api.v1.User
|
||||
2, // 59: memos.api.v1.UserService.CreateUser:output_type -> memos.api.v1.User
|
||||
2, // 60: memos.api.v1.UserService.UpdateUser:output_type -> memos.api.v1.User
|
||||
44, // 61: memos.api.v1.UserService.DeleteUser:output_type -> google.protobuf.Empty
|
||||
45, // 62: memos.api.v1.UserService.GetUserAvatar:output_type -> google.api.HttpBody
|
||||
13, // 63: memos.api.v1.UserService.ListAllUserStats:output_type -> memos.api.v1.ListAllUserStatsResponse
|
||||
10, // 64: memos.api.v1.UserService.GetUserStats:output_type -> memos.api.v1.UserStats
|
||||
14, // 65: memos.api.v1.UserService.GetUserSetting:output_type -> memos.api.v1.UserSetting
|
||||
14, // 66: memos.api.v1.UserService.UpdateUserSetting:output_type -> memos.api.v1.UserSetting
|
||||
18, // 67: memos.api.v1.UserService.ListUserSettings:output_type -> memos.api.v1.ListUserSettingsResponse
|
||||
21, // 68: memos.api.v1.UserService.ListUserAccessTokens:output_type -> memos.api.v1.ListUserAccessTokensResponse
|
||||
19, // 69: memos.api.v1.UserService.CreateUserAccessToken:output_type -> memos.api.v1.UserAccessToken
|
||||
44, // 70: memos.api.v1.UserService.DeleteUserAccessToken:output_type -> google.protobuf.Empty
|
||||
26, // 71: memos.api.v1.UserService.ListUserSessions:output_type -> memos.api.v1.ListUserSessionsResponse
|
||||
44, // 72: memos.api.v1.UserService.RevokeUserSession:output_type -> google.protobuf.Empty
|
||||
30, // 73: memos.api.v1.UserService.ListUserWebhooks:output_type -> memos.api.v1.ListUserWebhooksResponse
|
||||
28, // 74: memos.api.v1.UserService.CreateUserWebhook:output_type -> memos.api.v1.UserWebhook
|
||||
28, // 75: memos.api.v1.UserService.UpdateUserWebhook:output_type -> memos.api.v1.UserWebhook
|
||||
44, // 76: memos.api.v1.UserService.DeleteUserWebhook:output_type -> google.protobuf.Empty
|
||||
57, // [57:77] is the sub-list for method output_type
|
||||
37, // [37:57] is the sub-list for method input_type
|
||||
37, // [37:37] is the sub-list for extension type_name
|
||||
37, // [37:37] is the sub-list for extension extendee
|
||||
0, // [0:37] is the sub-list for field type_name
|
||||
48, // 1: memos.api.v1.User.state:type_name -> memos.api.v1.State
|
||||
49, // 2: memos.api.v1.User.create_time:type_name -> google.protobuf.Timestamp
|
||||
49, // 3: memos.api.v1.User.update_time:type_name -> google.protobuf.Timestamp
|
||||
4, // 4: memos.api.v1.ListUsersResponse.users:type_name -> memos.api.v1.User
|
||||
50, // 5: memos.api.v1.GetUserRequest.read_mask:type_name -> google.protobuf.FieldMask
|
||||
4, // 6: memos.api.v1.CreateUserRequest.user:type_name -> memos.api.v1.User
|
||||
4, // 7: memos.api.v1.UpdateUserRequest.user:type_name -> memos.api.v1.User
|
||||
50, // 8: memos.api.v1.UpdateUserRequest.update_mask:type_name -> google.protobuf.FieldMask
|
||||
49, // 9: memos.api.v1.UserStats.memo_display_timestamps:type_name -> google.protobuf.Timestamp
|
||||
42, // 10: memos.api.v1.UserStats.memo_type_stats:type_name -> memos.api.v1.UserStats.MemoTypeStats
|
||||
41, // 11: memos.api.v1.UserStats.tag_count:type_name -> memos.api.v1.UserStats.TagCountEntry
|
||||
12, // 12: memos.api.v1.ListAllUserStatsResponse.stats:type_name -> memos.api.v1.UserStats
|
||||
43, // 13: memos.api.v1.UserSetting.general_setting:type_name -> memos.api.v1.UserSetting.GeneralSetting
|
||||
44, // 14: memos.api.v1.UserSetting.sessions_setting:type_name -> memos.api.v1.UserSetting.SessionsSetting
|
||||
45, // 15: memos.api.v1.UserSetting.access_tokens_setting:type_name -> memos.api.v1.UserSetting.AccessTokensSetting
|
||||
46, // 16: memos.api.v1.UserSetting.webhooks_setting:type_name -> memos.api.v1.UserSetting.WebhooksSetting
|
||||
16, // 17: memos.api.v1.UpdateUserSettingRequest.setting:type_name -> memos.api.v1.UserSetting
|
||||
50, // 18: memos.api.v1.UpdateUserSettingRequest.update_mask:type_name -> google.protobuf.FieldMask
|
||||
16, // 19: memos.api.v1.ListUserSettingsResponse.settings:type_name -> memos.api.v1.UserSetting
|
||||
49, // 20: memos.api.v1.UserAccessToken.issued_at:type_name -> google.protobuf.Timestamp
|
||||
49, // 21: memos.api.v1.UserAccessToken.expires_at:type_name -> google.protobuf.Timestamp
|
||||
21, // 22: memos.api.v1.ListUserAccessTokensResponse.access_tokens:type_name -> memos.api.v1.UserAccessToken
|
||||
21, // 23: memos.api.v1.CreateUserAccessTokenRequest.access_token:type_name -> memos.api.v1.UserAccessToken
|
||||
49, // 24: memos.api.v1.UserSession.create_time:type_name -> google.protobuf.Timestamp
|
||||
49, // 25: memos.api.v1.UserSession.last_accessed_time:type_name -> google.protobuf.Timestamp
|
||||
47, // 26: memos.api.v1.UserSession.client_info:type_name -> memos.api.v1.UserSession.ClientInfo
|
||||
26, // 27: memos.api.v1.ListUserSessionsResponse.sessions:type_name -> memos.api.v1.UserSession
|
||||
49, // 28: memos.api.v1.UserWebhook.create_time:type_name -> google.protobuf.Timestamp
|
||||
49, // 29: memos.api.v1.UserWebhook.update_time:type_name -> google.protobuf.Timestamp
|
||||
30, // 30: memos.api.v1.ListUserWebhooksResponse.webhooks:type_name -> memos.api.v1.UserWebhook
|
||||
30, // 31: memos.api.v1.CreateUserWebhookRequest.webhook:type_name -> memos.api.v1.UserWebhook
|
||||
30, // 32: memos.api.v1.UpdateUserWebhookRequest.webhook:type_name -> memos.api.v1.UserWebhook
|
||||
50, // 33: memos.api.v1.UpdateUserWebhookRequest.update_mask:type_name -> google.protobuf.FieldMask
|
||||
2, // 34: memos.api.v1.UserNotification.status:type_name -> memos.api.v1.UserNotification.Status
|
||||
49, // 35: memos.api.v1.UserNotification.create_time:type_name -> google.protobuf.Timestamp
|
||||
3, // 36: memos.api.v1.UserNotification.type:type_name -> memos.api.v1.UserNotification.Type
|
||||
36, // 37: memos.api.v1.ListUserNotificationsResponse.notifications:type_name -> memos.api.v1.UserNotification
|
||||
36, // 38: memos.api.v1.UpdateUserNotificationRequest.notification:type_name -> memos.api.v1.UserNotification
|
||||
50, // 39: memos.api.v1.UpdateUserNotificationRequest.update_mask:type_name -> google.protobuf.FieldMask
|
||||
26, // 40: memos.api.v1.UserSetting.SessionsSetting.sessions:type_name -> memos.api.v1.UserSession
|
||||
21, // 41: memos.api.v1.UserSetting.AccessTokensSetting.access_tokens:type_name -> memos.api.v1.UserAccessToken
|
||||
30, // 42: memos.api.v1.UserSetting.WebhooksSetting.webhooks:type_name -> memos.api.v1.UserWebhook
|
||||
5, // 43: memos.api.v1.UserService.ListUsers:input_type -> memos.api.v1.ListUsersRequest
|
||||
7, // 44: memos.api.v1.UserService.GetUser:input_type -> memos.api.v1.GetUserRequest
|
||||
8, // 45: memos.api.v1.UserService.CreateUser:input_type -> memos.api.v1.CreateUserRequest
|
||||
9, // 46: memos.api.v1.UserService.UpdateUser:input_type -> memos.api.v1.UpdateUserRequest
|
||||
10, // 47: memos.api.v1.UserService.DeleteUser:input_type -> memos.api.v1.DeleteUserRequest
|
||||
11, // 48: memos.api.v1.UserService.GetUserAvatar:input_type -> memos.api.v1.GetUserAvatarRequest
|
||||
14, // 49: memos.api.v1.UserService.ListAllUserStats:input_type -> memos.api.v1.ListAllUserStatsRequest
|
||||
13, // 50: memos.api.v1.UserService.GetUserStats:input_type -> memos.api.v1.GetUserStatsRequest
|
||||
17, // 51: memos.api.v1.UserService.GetUserSetting:input_type -> memos.api.v1.GetUserSettingRequest
|
||||
18, // 52: memos.api.v1.UserService.UpdateUserSetting:input_type -> memos.api.v1.UpdateUserSettingRequest
|
||||
19, // 53: memos.api.v1.UserService.ListUserSettings:input_type -> memos.api.v1.ListUserSettingsRequest
|
||||
22, // 54: memos.api.v1.UserService.ListUserAccessTokens:input_type -> memos.api.v1.ListUserAccessTokensRequest
|
||||
24, // 55: memos.api.v1.UserService.CreateUserAccessToken:input_type -> memos.api.v1.CreateUserAccessTokenRequest
|
||||
25, // 56: memos.api.v1.UserService.DeleteUserAccessToken:input_type -> memos.api.v1.DeleteUserAccessTokenRequest
|
||||
27, // 57: memos.api.v1.UserService.ListUserSessions:input_type -> memos.api.v1.ListUserSessionsRequest
|
||||
29, // 58: memos.api.v1.UserService.RevokeUserSession:input_type -> memos.api.v1.RevokeUserSessionRequest
|
||||
31, // 59: memos.api.v1.UserService.ListUserWebhooks:input_type -> memos.api.v1.ListUserWebhooksRequest
|
||||
33, // 60: memos.api.v1.UserService.CreateUserWebhook:input_type -> memos.api.v1.CreateUserWebhookRequest
|
||||
34, // 61: memos.api.v1.UserService.UpdateUserWebhook:input_type -> memos.api.v1.UpdateUserWebhookRequest
|
||||
35, // 62: memos.api.v1.UserService.DeleteUserWebhook:input_type -> memos.api.v1.DeleteUserWebhookRequest
|
||||
37, // 63: memos.api.v1.UserService.ListUserNotifications:input_type -> memos.api.v1.ListUserNotificationsRequest
|
||||
39, // 64: memos.api.v1.UserService.UpdateUserNotification:input_type -> memos.api.v1.UpdateUserNotificationRequest
|
||||
40, // 65: memos.api.v1.UserService.DeleteUserNotification:input_type -> memos.api.v1.DeleteUserNotificationRequest
|
||||
6, // 66: memos.api.v1.UserService.ListUsers:output_type -> memos.api.v1.ListUsersResponse
|
||||
4, // 67: memos.api.v1.UserService.GetUser:output_type -> memos.api.v1.User
|
||||
4, // 68: memos.api.v1.UserService.CreateUser:output_type -> memos.api.v1.User
|
||||
4, // 69: memos.api.v1.UserService.UpdateUser:output_type -> memos.api.v1.User
|
||||
51, // 70: memos.api.v1.UserService.DeleteUser:output_type -> google.protobuf.Empty
|
||||
52, // 71: memos.api.v1.UserService.GetUserAvatar:output_type -> google.api.HttpBody
|
||||
15, // 72: memos.api.v1.UserService.ListAllUserStats:output_type -> memos.api.v1.ListAllUserStatsResponse
|
||||
12, // 73: memos.api.v1.UserService.GetUserStats:output_type -> memos.api.v1.UserStats
|
||||
16, // 74: memos.api.v1.UserService.GetUserSetting:output_type -> memos.api.v1.UserSetting
|
||||
16, // 75: memos.api.v1.UserService.UpdateUserSetting:output_type -> memos.api.v1.UserSetting
|
||||
20, // 76: memos.api.v1.UserService.ListUserSettings:output_type -> memos.api.v1.ListUserSettingsResponse
|
||||
23, // 77: memos.api.v1.UserService.ListUserAccessTokens:output_type -> memos.api.v1.ListUserAccessTokensResponse
|
||||
21, // 78: memos.api.v1.UserService.CreateUserAccessToken:output_type -> memos.api.v1.UserAccessToken
|
||||
51, // 79: memos.api.v1.UserService.DeleteUserAccessToken:output_type -> google.protobuf.Empty
|
||||
28, // 80: memos.api.v1.UserService.ListUserSessions:output_type -> memos.api.v1.ListUserSessionsResponse
|
||||
51, // 81: memos.api.v1.UserService.RevokeUserSession:output_type -> google.protobuf.Empty
|
||||
32, // 82: memos.api.v1.UserService.ListUserWebhooks:output_type -> memos.api.v1.ListUserWebhooksResponse
|
||||
30, // 83: memos.api.v1.UserService.CreateUserWebhook:output_type -> memos.api.v1.UserWebhook
|
||||
30, // 84: memos.api.v1.UserService.UpdateUserWebhook:output_type -> memos.api.v1.UserWebhook
|
||||
51, // 85: memos.api.v1.UserService.DeleteUserWebhook:output_type -> google.protobuf.Empty
|
||||
38, // 86: memos.api.v1.UserService.ListUserNotifications:output_type -> memos.api.v1.ListUserNotificationsResponse
|
||||
36, // 87: memos.api.v1.UserService.UpdateUserNotification:output_type -> memos.api.v1.UserNotification
|
||||
51, // 88: memos.api.v1.UserService.DeleteUserNotification:output_type -> google.protobuf.Empty
|
||||
66, // [66:89] is the sub-list for method output_type
|
||||
43, // [43:66] is the sub-list for method input_type
|
||||
43, // [43:43] is the sub-list for extension type_name
|
||||
43, // [43:43] is the sub-list for extension extendee
|
||||
0, // [0:43] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_api_v1_user_service_proto_init() }
|
||||
|
|
@ -2911,13 +3376,14 @@ func file_api_v1_user_service_proto_init() {
|
|||
(*UserSetting_AccessTokensSetting_)(nil),
|
||||
(*UserSetting_WebhooksSetting_)(nil),
|
||||
}
|
||||
file_api_v1_user_service_proto_msgTypes[32].OneofWrappers = []any{}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_api_v1_user_service_proto_rawDesc), len(file_api_v1_user_service_proto_rawDesc)),
|
||||
NumEnums: 2,
|
||||
NumMessages: 39,
|
||||
NumEnums: 4,
|
||||
NumMessages: 44,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1003,6 +1003,179 @@ func local_request_UserService_DeleteUserWebhook_0(ctx context.Context, marshale
|
|||
return msg, metadata, err
|
||||
}
|
||||
|
||||
var filter_UserService_ListUserNotifications_0 = &utilities.DoubleArray{Encoding: map[string]int{"parent": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
|
||||
|
||||
func request_UserService_ListUserNotifications_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var (
|
||||
protoReq ListUserNotificationsRequest
|
||||
metadata runtime.ServerMetadata
|
||||
err error
|
||||
)
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
val, ok := pathParams["parent"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "parent")
|
||||
}
|
||||
protoReq.Parent, err = runtime.String(val)
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "parent", err)
|
||||
}
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_UserService_ListUserNotifications_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
msg, err := client.ListUserNotifications(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
}
|
||||
|
||||
func local_request_UserService_ListUserNotifications_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var (
|
||||
protoReq ListUserNotificationsRequest
|
||||
metadata runtime.ServerMetadata
|
||||
err error
|
||||
)
|
||||
val, ok := pathParams["parent"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "parent")
|
||||
}
|
||||
protoReq.Parent, err = runtime.String(val)
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "parent", err)
|
||||
}
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_UserService_ListUserNotifications_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
msg, err := server.ListUserNotifications(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
}
|
||||
|
||||
var filter_UserService_UpdateUserNotification_0 = &utilities.DoubleArray{Encoding: map[string]int{"notification": 0, "name": 1}, Base: []int{1, 2, 1, 0, 0}, Check: []int{0, 1, 2, 3, 2}}
|
||||
|
||||
func request_UserService_UpdateUserNotification_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var (
|
||||
protoReq UpdateUserNotificationRequest
|
||||
metadata runtime.ServerMetadata
|
||||
err error
|
||||
)
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Notification); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 {
|
||||
if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Notification); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
} else {
|
||||
protoReq.UpdateMask = fieldMask
|
||||
}
|
||||
}
|
||||
val, ok := pathParams["notification.name"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "notification.name")
|
||||
}
|
||||
err = runtime.PopulateFieldFromPath(&protoReq, "notification.name", val)
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "notification.name", err)
|
||||
}
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_UserService_UpdateUserNotification_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
msg, err := client.UpdateUserNotification(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
}
|
||||
|
||||
func local_request_UserService_UpdateUserNotification_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var (
|
||||
protoReq UpdateUserNotificationRequest
|
||||
metadata runtime.ServerMetadata
|
||||
err error
|
||||
)
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Notification); err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 {
|
||||
if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Notification); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
} else {
|
||||
protoReq.UpdateMask = fieldMask
|
||||
}
|
||||
}
|
||||
val, ok := pathParams["notification.name"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "notification.name")
|
||||
}
|
||||
err = runtime.PopulateFieldFromPath(&protoReq, "notification.name", val)
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "notification.name", err)
|
||||
}
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_UserService_UpdateUserNotification_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
msg, err := server.UpdateUserNotification(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
}
|
||||
|
||||
func request_UserService_DeleteUserNotification_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var (
|
||||
protoReq DeleteUserNotificationRequest
|
||||
metadata runtime.ServerMetadata
|
||||
err error
|
||||
)
|
||||
if req.Body != nil {
|
||||
_, _ = io.Copy(io.Discard, req.Body)
|
||||
}
|
||||
val, ok := pathParams["name"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
|
||||
}
|
||||
protoReq.Name, err = runtime.String(val)
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||
}
|
||||
msg, err := client.DeleteUserNotification(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
}
|
||||
|
||||
func local_request_UserService_DeleteUserNotification_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var (
|
||||
protoReq DeleteUserNotificationRequest
|
||||
metadata runtime.ServerMetadata
|
||||
err error
|
||||
)
|
||||
val, ok := pathParams["name"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
|
||||
}
|
||||
protoReq.Name, err = runtime.String(val)
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||
}
|
||||
msg, err := server.DeleteUserNotification(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
}
|
||||
|
||||
// RegisterUserServiceHandlerServer registers the http handlers for service UserService to "mux".
|
||||
// UnaryRPC :call UserServiceServer directly.
|
||||
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
||||
|
|
@ -1409,6 +1582,66 @@ func RegisterUserServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux
|
|||
}
|
||||
forward_UserService_DeleteUserWebhook_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
})
|
||||
mux.Handle(http.MethodGet, pattern_UserService_ListUserNotifications_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.UserService/ListUserNotifications", runtime.WithHTTPPathPattern("/api/v1/{parent=users/*}/notifications"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_UserService_ListUserNotifications_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
forward_UserService_ListUserNotifications_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
})
|
||||
mux.Handle(http.MethodPatch, pattern_UserService_UpdateUserNotification_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.UserService/UpdateUserNotification", runtime.WithHTTPPathPattern("/api/v1/{notification.name=users/*/notifications/*}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_UserService_UpdateUserNotification_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
forward_UserService_UpdateUserNotification_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
})
|
||||
mux.Handle(http.MethodDelete, pattern_UserService_DeleteUserNotification_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.UserService/DeleteUserNotification", runtime.WithHTTPPathPattern("/api/v1/{name=users/*/notifications/*}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_UserService_DeleteUserNotification_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
forward_UserService_DeleteUserNotification_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1789,51 +2022,108 @@ func RegisterUserServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux
|
|||
}
|
||||
forward_UserService_DeleteUserWebhook_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
})
|
||||
mux.Handle(http.MethodGet, pattern_UserService_ListUserNotifications_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.UserService/ListUserNotifications", runtime.WithHTTPPathPattern("/api/v1/{parent=users/*}/notifications"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_UserService_ListUserNotifications_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
forward_UserService_ListUserNotifications_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
})
|
||||
mux.Handle(http.MethodPatch, pattern_UserService_UpdateUserNotification_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.UserService/UpdateUserNotification", runtime.WithHTTPPathPattern("/api/v1/{notification.name=users/*/notifications/*}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_UserService_UpdateUserNotification_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
forward_UserService_UpdateUserNotification_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
})
|
||||
mux.Handle(http.MethodDelete, pattern_UserService_DeleteUserNotification_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.UserService/DeleteUserNotification", runtime.WithHTTPPathPattern("/api/v1/{name=users/*/notifications/*}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_UserService_DeleteUserNotification_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
forward_UserService_DeleteUserNotification_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
pattern_UserService_ListUsers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "users"}, ""))
|
||||
pattern_UserService_GetUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "users", "name"}, ""))
|
||||
pattern_UserService_CreateUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "users"}, ""))
|
||||
pattern_UserService_UpdateUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "users", "user.name"}, ""))
|
||||
pattern_UserService_DeleteUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "users", "name"}, ""))
|
||||
pattern_UserService_GetUserAvatar_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "users", "name", "avatar"}, ""))
|
||||
pattern_UserService_ListAllUserStats_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "users"}, "stats"))
|
||||
pattern_UserService_GetUserStats_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "users", "name"}, "getStats"))
|
||||
pattern_UserService_GetUserSetting_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 2, 3, 1, 0, 4, 4, 5, 4}, []string{"api", "v1", "users", "settings", "name"}, ""))
|
||||
pattern_UserService_UpdateUserSetting_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 2, 3, 1, 0, 4, 4, 5, 4}, []string{"api", "v1", "users", "settings", "setting.name"}, ""))
|
||||
pattern_UserService_ListUserSettings_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "users", "parent", "settings"}, ""))
|
||||
pattern_UserService_ListUserAccessTokens_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "users", "parent", "accessTokens"}, ""))
|
||||
pattern_UserService_CreateUserAccessToken_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "users", "parent", "accessTokens"}, ""))
|
||||
pattern_UserService_DeleteUserAccessToken_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 2, 3, 1, 0, 4, 4, 5, 4}, []string{"api", "v1", "users", "accessTokens", "name"}, ""))
|
||||
pattern_UserService_ListUserSessions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "users", "parent", "sessions"}, ""))
|
||||
pattern_UserService_RevokeUserSession_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 2, 3, 1, 0, 4, 4, 5, 4}, []string{"api", "v1", "users", "sessions", "name"}, ""))
|
||||
pattern_UserService_ListUserWebhooks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "users", "parent", "webhooks"}, ""))
|
||||
pattern_UserService_CreateUserWebhook_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "users", "parent", "webhooks"}, ""))
|
||||
pattern_UserService_UpdateUserWebhook_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 2, 3, 1, 0, 4, 4, 5, 4}, []string{"api", "v1", "users", "webhooks", "webhook.name"}, ""))
|
||||
pattern_UserService_DeleteUserWebhook_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 2, 3, 1, 0, 4, 4, 5, 4}, []string{"api", "v1", "users", "webhooks", "name"}, ""))
|
||||
pattern_UserService_ListUsers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "users"}, ""))
|
||||
pattern_UserService_GetUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "users", "name"}, ""))
|
||||
pattern_UserService_CreateUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "users"}, ""))
|
||||
pattern_UserService_UpdateUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "users", "user.name"}, ""))
|
||||
pattern_UserService_DeleteUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "users", "name"}, ""))
|
||||
pattern_UserService_GetUserAvatar_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "users", "name", "avatar"}, ""))
|
||||
pattern_UserService_ListAllUserStats_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "users"}, "stats"))
|
||||
pattern_UserService_GetUserStats_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "users", "name"}, "getStats"))
|
||||
pattern_UserService_GetUserSetting_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 2, 3, 1, 0, 4, 4, 5, 4}, []string{"api", "v1", "users", "settings", "name"}, ""))
|
||||
pattern_UserService_UpdateUserSetting_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 2, 3, 1, 0, 4, 4, 5, 4}, []string{"api", "v1", "users", "settings", "setting.name"}, ""))
|
||||
pattern_UserService_ListUserSettings_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "users", "parent", "settings"}, ""))
|
||||
pattern_UserService_ListUserAccessTokens_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "users", "parent", "accessTokens"}, ""))
|
||||
pattern_UserService_CreateUserAccessToken_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "users", "parent", "accessTokens"}, ""))
|
||||
pattern_UserService_DeleteUserAccessToken_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 2, 3, 1, 0, 4, 4, 5, 4}, []string{"api", "v1", "users", "accessTokens", "name"}, ""))
|
||||
pattern_UserService_ListUserSessions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "users", "parent", "sessions"}, ""))
|
||||
pattern_UserService_RevokeUserSession_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 2, 3, 1, 0, 4, 4, 5, 4}, []string{"api", "v1", "users", "sessions", "name"}, ""))
|
||||
pattern_UserService_ListUserWebhooks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "users", "parent", "webhooks"}, ""))
|
||||
pattern_UserService_CreateUserWebhook_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "users", "parent", "webhooks"}, ""))
|
||||
pattern_UserService_UpdateUserWebhook_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 2, 3, 1, 0, 4, 4, 5, 4}, []string{"api", "v1", "users", "webhooks", "webhook.name"}, ""))
|
||||
pattern_UserService_DeleteUserWebhook_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 2, 3, 1, 0, 4, 4, 5, 4}, []string{"api", "v1", "users", "webhooks", "name"}, ""))
|
||||
pattern_UserService_ListUserNotifications_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "users", "parent", "notifications"}, ""))
|
||||
pattern_UserService_UpdateUserNotification_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 2, 3, 1, 0, 4, 4, 5, 4}, []string{"api", "v1", "users", "notifications", "notification.name"}, ""))
|
||||
pattern_UserService_DeleteUserNotification_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 2, 3, 1, 0, 4, 4, 5, 4}, []string{"api", "v1", "users", "notifications", "name"}, ""))
|
||||
)
|
||||
|
||||
var (
|
||||
forward_UserService_ListUsers_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_GetUser_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_CreateUser_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_UpdateUser_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_DeleteUser_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_GetUserAvatar_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_ListAllUserStats_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_GetUserStats_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_GetUserSetting_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_UpdateUserSetting_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_ListUserSettings_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_ListUserAccessTokens_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_CreateUserAccessToken_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_DeleteUserAccessToken_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_ListUserSessions_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_RevokeUserSession_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_ListUserWebhooks_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_CreateUserWebhook_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_UpdateUserWebhook_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_DeleteUserWebhook_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_ListUsers_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_GetUser_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_CreateUser_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_UpdateUser_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_DeleteUser_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_GetUserAvatar_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_ListAllUserStats_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_GetUserStats_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_GetUserSetting_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_UpdateUserSetting_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_ListUserSettings_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_ListUserAccessTokens_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_CreateUserAccessToken_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_DeleteUserAccessToken_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_ListUserSessions_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_RevokeUserSession_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_ListUserWebhooks_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_CreateUserWebhook_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_UpdateUserWebhook_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_DeleteUserWebhook_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_ListUserNotifications_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_UpdateUserNotification_0 = runtime.ForwardResponseMessage
|
||||
forward_UserService_DeleteUserNotification_0 = runtime.ForwardResponseMessage
|
||||
)
|
||||
|
|
|
|||
|
|
@ -21,26 +21,29 @@ import (
|
|||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
UserService_ListUsers_FullMethodName = "/memos.api.v1.UserService/ListUsers"
|
||||
UserService_GetUser_FullMethodName = "/memos.api.v1.UserService/GetUser"
|
||||
UserService_CreateUser_FullMethodName = "/memos.api.v1.UserService/CreateUser"
|
||||
UserService_UpdateUser_FullMethodName = "/memos.api.v1.UserService/UpdateUser"
|
||||
UserService_DeleteUser_FullMethodName = "/memos.api.v1.UserService/DeleteUser"
|
||||
UserService_GetUserAvatar_FullMethodName = "/memos.api.v1.UserService/GetUserAvatar"
|
||||
UserService_ListAllUserStats_FullMethodName = "/memos.api.v1.UserService/ListAllUserStats"
|
||||
UserService_GetUserStats_FullMethodName = "/memos.api.v1.UserService/GetUserStats"
|
||||
UserService_GetUserSetting_FullMethodName = "/memos.api.v1.UserService/GetUserSetting"
|
||||
UserService_UpdateUserSetting_FullMethodName = "/memos.api.v1.UserService/UpdateUserSetting"
|
||||
UserService_ListUserSettings_FullMethodName = "/memos.api.v1.UserService/ListUserSettings"
|
||||
UserService_ListUserAccessTokens_FullMethodName = "/memos.api.v1.UserService/ListUserAccessTokens"
|
||||
UserService_CreateUserAccessToken_FullMethodName = "/memos.api.v1.UserService/CreateUserAccessToken"
|
||||
UserService_DeleteUserAccessToken_FullMethodName = "/memos.api.v1.UserService/DeleteUserAccessToken"
|
||||
UserService_ListUserSessions_FullMethodName = "/memos.api.v1.UserService/ListUserSessions"
|
||||
UserService_RevokeUserSession_FullMethodName = "/memos.api.v1.UserService/RevokeUserSession"
|
||||
UserService_ListUserWebhooks_FullMethodName = "/memos.api.v1.UserService/ListUserWebhooks"
|
||||
UserService_CreateUserWebhook_FullMethodName = "/memos.api.v1.UserService/CreateUserWebhook"
|
||||
UserService_UpdateUserWebhook_FullMethodName = "/memos.api.v1.UserService/UpdateUserWebhook"
|
||||
UserService_DeleteUserWebhook_FullMethodName = "/memos.api.v1.UserService/DeleteUserWebhook"
|
||||
UserService_ListUsers_FullMethodName = "/memos.api.v1.UserService/ListUsers"
|
||||
UserService_GetUser_FullMethodName = "/memos.api.v1.UserService/GetUser"
|
||||
UserService_CreateUser_FullMethodName = "/memos.api.v1.UserService/CreateUser"
|
||||
UserService_UpdateUser_FullMethodName = "/memos.api.v1.UserService/UpdateUser"
|
||||
UserService_DeleteUser_FullMethodName = "/memos.api.v1.UserService/DeleteUser"
|
||||
UserService_GetUserAvatar_FullMethodName = "/memos.api.v1.UserService/GetUserAvatar"
|
||||
UserService_ListAllUserStats_FullMethodName = "/memos.api.v1.UserService/ListAllUserStats"
|
||||
UserService_GetUserStats_FullMethodName = "/memos.api.v1.UserService/GetUserStats"
|
||||
UserService_GetUserSetting_FullMethodName = "/memos.api.v1.UserService/GetUserSetting"
|
||||
UserService_UpdateUserSetting_FullMethodName = "/memos.api.v1.UserService/UpdateUserSetting"
|
||||
UserService_ListUserSettings_FullMethodName = "/memos.api.v1.UserService/ListUserSettings"
|
||||
UserService_ListUserAccessTokens_FullMethodName = "/memos.api.v1.UserService/ListUserAccessTokens"
|
||||
UserService_CreateUserAccessToken_FullMethodName = "/memos.api.v1.UserService/CreateUserAccessToken"
|
||||
UserService_DeleteUserAccessToken_FullMethodName = "/memos.api.v1.UserService/DeleteUserAccessToken"
|
||||
UserService_ListUserSessions_FullMethodName = "/memos.api.v1.UserService/ListUserSessions"
|
||||
UserService_RevokeUserSession_FullMethodName = "/memos.api.v1.UserService/RevokeUserSession"
|
||||
UserService_ListUserWebhooks_FullMethodName = "/memos.api.v1.UserService/ListUserWebhooks"
|
||||
UserService_CreateUserWebhook_FullMethodName = "/memos.api.v1.UserService/CreateUserWebhook"
|
||||
UserService_UpdateUserWebhook_FullMethodName = "/memos.api.v1.UserService/UpdateUserWebhook"
|
||||
UserService_DeleteUserWebhook_FullMethodName = "/memos.api.v1.UserService/DeleteUserWebhook"
|
||||
UserService_ListUserNotifications_FullMethodName = "/memos.api.v1.UserService/ListUserNotifications"
|
||||
UserService_UpdateUserNotification_FullMethodName = "/memos.api.v1.UserService/UpdateUserNotification"
|
||||
UserService_DeleteUserNotification_FullMethodName = "/memos.api.v1.UserService/DeleteUserNotification"
|
||||
)
|
||||
|
||||
// UserServiceClient is the client API for UserService service.
|
||||
|
|
@ -90,6 +93,12 @@ type UserServiceClient interface {
|
|||
UpdateUserWebhook(ctx context.Context, in *UpdateUserWebhookRequest, opts ...grpc.CallOption) (*UserWebhook, error)
|
||||
// DeleteUserWebhook deletes a webhook for a user.
|
||||
DeleteUserWebhook(ctx context.Context, in *DeleteUserWebhookRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||
// ListUserNotifications lists notifications for a user.
|
||||
ListUserNotifications(ctx context.Context, in *ListUserNotificationsRequest, opts ...grpc.CallOption) (*ListUserNotificationsResponse, error)
|
||||
// UpdateUserNotification updates a notification.
|
||||
UpdateUserNotification(ctx context.Context, in *UpdateUserNotificationRequest, opts ...grpc.CallOption) (*UserNotification, error)
|
||||
// DeleteUserNotification deletes a notification.
|
||||
DeleteUserNotification(ctx context.Context, in *DeleteUserNotificationRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||
}
|
||||
|
||||
type userServiceClient struct {
|
||||
|
|
@ -300,6 +309,36 @@ func (c *userServiceClient) DeleteUserWebhook(ctx context.Context, in *DeleteUse
|
|||
return out, nil
|
||||
}
|
||||
|
||||
func (c *userServiceClient) ListUserNotifications(ctx context.Context, in *ListUserNotificationsRequest, opts ...grpc.CallOption) (*ListUserNotificationsResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListUserNotificationsResponse)
|
||||
err := c.cc.Invoke(ctx, UserService_ListUserNotifications_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *userServiceClient) UpdateUserNotification(ctx context.Context, in *UpdateUserNotificationRequest, opts ...grpc.CallOption) (*UserNotification, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(UserNotification)
|
||||
err := c.cc.Invoke(ctx, UserService_UpdateUserNotification_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *userServiceClient) DeleteUserNotification(ctx context.Context, in *DeleteUserNotificationRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(emptypb.Empty)
|
||||
err := c.cc.Invoke(ctx, UserService_DeleteUserNotification_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// UserServiceServer is the server API for UserService service.
|
||||
// All implementations must embed UnimplementedUserServiceServer
|
||||
// for forward compatibility.
|
||||
|
|
@ -347,6 +386,12 @@ type UserServiceServer interface {
|
|||
UpdateUserWebhook(context.Context, *UpdateUserWebhookRequest) (*UserWebhook, error)
|
||||
// DeleteUserWebhook deletes a webhook for a user.
|
||||
DeleteUserWebhook(context.Context, *DeleteUserWebhookRequest) (*emptypb.Empty, error)
|
||||
// ListUserNotifications lists notifications for a user.
|
||||
ListUserNotifications(context.Context, *ListUserNotificationsRequest) (*ListUserNotificationsResponse, error)
|
||||
// UpdateUserNotification updates a notification.
|
||||
UpdateUserNotification(context.Context, *UpdateUserNotificationRequest) (*UserNotification, error)
|
||||
// DeleteUserNotification deletes a notification.
|
||||
DeleteUserNotification(context.Context, *DeleteUserNotificationRequest) (*emptypb.Empty, error)
|
||||
mustEmbedUnimplementedUserServiceServer()
|
||||
}
|
||||
|
||||
|
|
@ -417,6 +462,15 @@ func (UnimplementedUserServiceServer) UpdateUserWebhook(context.Context, *Update
|
|||
func (UnimplementedUserServiceServer) DeleteUserWebhook(context.Context, *DeleteUserWebhookRequest) (*emptypb.Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DeleteUserWebhook not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) ListUserNotifications(context.Context, *ListUserNotificationsRequest) (*ListUserNotificationsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListUserNotifications not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) UpdateUserNotification(context.Context, *UpdateUserNotificationRequest) (*UserNotification, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateUserNotification not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) DeleteUserNotification(context.Context, *DeleteUserNotificationRequest) (*emptypb.Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DeleteUserNotification not implemented")
|
||||
}
|
||||
func (UnimplementedUserServiceServer) mustEmbedUnimplementedUserServiceServer() {}
|
||||
func (UnimplementedUserServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
|
|
@ -798,6 +852,60 @@ func _UserService_DeleteUserWebhook_Handler(srv interface{}, ctx context.Context
|
|||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _UserService_ListUserNotifications_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListUserNotificationsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(UserServiceServer).ListUserNotifications(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: UserService_ListUserNotifications_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(UserServiceServer).ListUserNotifications(ctx, req.(*ListUserNotificationsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _UserService_UpdateUserNotification_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(UpdateUserNotificationRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(UserServiceServer).UpdateUserNotification(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: UserService_UpdateUserNotification_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(UserServiceServer).UpdateUserNotification(ctx, req.(*UpdateUserNotificationRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _UserService_DeleteUserNotification_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(DeleteUserNotificationRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(UserServiceServer).DeleteUserNotification(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: UserService_DeleteUserNotification_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(UserServiceServer).DeleteUserNotification(ctx, req.(*DeleteUserNotificationRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// UserService_ServiceDesc is the grpc.ServiceDesc for UserService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
|
|
@ -885,6 +993,18 @@ var UserService_ServiceDesc = grpc.ServiceDesc{
|
|||
MethodName: "DeleteUserWebhook",
|
||||
Handler: _UserService_DeleteUserWebhook_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListUserNotifications",
|
||||
Handler: _UserService_ListUserNotifications_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "UpdateUserNotification",
|
||||
Handler: _UserService_UpdateUserNotification_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "DeleteUserNotification",
|
||||
Handler: _UserService_DeleteUserNotification_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "api/v1/user_service.proto",
|
||||
|
|
|
|||
|
|
@ -442,71 +442,6 @@ paths:
|
|||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Status'
|
||||
/api/v1/inboxes/{inboxe}:
|
||||
delete:
|
||||
tags:
|
||||
- InboxService
|
||||
description: DeleteInbox deletes an inbox.
|
||||
operationId: InboxService_DeleteInbox
|
||||
parameters:
|
||||
- name: inboxe
|
||||
in: path
|
||||
description: The inboxe id.
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content: {}
|
||||
default:
|
||||
description: Default error response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Status'
|
||||
patch:
|
||||
tags:
|
||||
- InboxService
|
||||
description: UpdateInbox updates an inbox.
|
||||
operationId: InboxService_UpdateInbox
|
||||
parameters:
|
||||
- name: inboxe
|
||||
in: path
|
||||
description: The inboxe id.
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: updateMask
|
||||
in: query
|
||||
description: Required. The list of fields to update.
|
||||
schema:
|
||||
type: string
|
||||
format: field-mask
|
||||
- name: allowMissing
|
||||
in: query
|
||||
description: Optional. If set to true, allows updating missing fields.
|
||||
schema:
|
||||
type: boolean
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Inbox'
|
||||
required: true
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Inbox'
|
||||
default:
|
||||
description: Default error response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Status'
|
||||
/api/v1/memos:
|
||||
get:
|
||||
tags:
|
||||
|
|
@ -1329,12 +1264,12 @@ paths:
|
|||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Status'
|
||||
/api/v1/users/{user}/inboxes:
|
||||
/api/v1/users/{user}/notifications:
|
||||
get:
|
||||
tags:
|
||||
- InboxService
|
||||
description: ListInboxes lists inboxes for a user.
|
||||
operationId: InboxService_ListInboxes
|
||||
- UserService
|
||||
description: ListUserNotifications lists notifications for a user.
|
||||
operationId: UserService_ListUserNotifications
|
||||
parameters:
|
||||
- name: user
|
||||
in: path
|
||||
|
|
@ -1344,35 +1279,15 @@ paths:
|
|||
type: string
|
||||
- name: pageSize
|
||||
in: query
|
||||
description: |-
|
||||
Optional. The maximum number of inboxes to return.
|
||||
The service may return fewer than this value.
|
||||
If unspecified, at most 50 inboxes will be returned.
|
||||
The maximum value is 1000; values above 1000 will be coerced to 1000.
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
- name: pageToken
|
||||
in: query
|
||||
description: |-
|
||||
Optional. A page token, received from a previous `ListInboxes` call.
|
||||
Provide this to retrieve the subsequent page.
|
||||
schema:
|
||||
type: string
|
||||
- name: filter
|
||||
in: query
|
||||
description: |-
|
||||
Optional. Filter to apply to the list results.
|
||||
Example: "status=UNREAD" or "type=MEMO_COMMENT"
|
||||
Supported operators: =, !=
|
||||
Supported fields: status, type, sender, create_time
|
||||
schema:
|
||||
type: string
|
||||
- name: orderBy
|
||||
in: query
|
||||
description: |-
|
||||
Optional. The order to sort results by.
|
||||
Example: "create_time desc" or "status asc"
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
|
|
@ -1381,7 +1296,78 @@ paths:
|
|||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ListInboxesResponse'
|
||||
$ref: '#/components/schemas/ListUserNotificationsResponse'
|
||||
default:
|
||||
description: Default error response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Status'
|
||||
/api/v1/users/{user}/notifications/{notification}:
|
||||
delete:
|
||||
tags:
|
||||
- UserService
|
||||
description: DeleteUserNotification deletes a notification.
|
||||
operationId: UserService_DeleteUserNotification
|
||||
parameters:
|
||||
- name: user
|
||||
in: path
|
||||
description: The user id.
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: notification
|
||||
in: path
|
||||
description: The notification id.
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content: {}
|
||||
default:
|
||||
description: Default error response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Status'
|
||||
patch:
|
||||
tags:
|
||||
- UserService
|
||||
description: UpdateUserNotification updates a notification.
|
||||
operationId: UserService_UpdateUserNotification
|
||||
parameters:
|
||||
- name: user
|
||||
in: path
|
||||
description: The user id.
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: notification
|
||||
in: path
|
||||
description: The notification id.
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: updateMask
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
format: field-mask
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UserNotification'
|
||||
required: true
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UserNotification'
|
||||
default:
|
||||
description: Default error response
|
||||
content:
|
||||
|
|
@ -2039,7 +2025,6 @@ components:
|
|||
enum:
|
||||
- TYPE_UNSPECIFIED
|
||||
- MEMO_COMMENT
|
||||
- VERSION_UPDATE
|
||||
type: string
|
||||
description: The type of the activity.
|
||||
format: enum
|
||||
|
|
@ -2264,52 +2249,6 @@ components:
|
|||
properties:
|
||||
oauth2Config:
|
||||
$ref: '#/components/schemas/OAuth2Config'
|
||||
Inbox:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: |-
|
||||
The resource name of the inbox.
|
||||
Format: inboxes/{inbox}
|
||||
sender:
|
||||
readOnly: true
|
||||
type: string
|
||||
description: |-
|
||||
The sender of the inbox notification.
|
||||
Format: users/{user}
|
||||
receiver:
|
||||
readOnly: true
|
||||
type: string
|
||||
description: |-
|
||||
The receiver of the inbox notification.
|
||||
Format: users/{user}
|
||||
status:
|
||||
enum:
|
||||
- STATUS_UNSPECIFIED
|
||||
- UNREAD
|
||||
- ARCHIVED
|
||||
type: string
|
||||
description: The status of the inbox notification.
|
||||
format: enum
|
||||
createTime:
|
||||
readOnly: true
|
||||
type: string
|
||||
description: Output only. The creation timestamp.
|
||||
format: date-time
|
||||
type:
|
||||
readOnly: true
|
||||
enum:
|
||||
- TYPE_UNSPECIFIED
|
||||
- MEMO_COMMENT
|
||||
- VERSION_UPDATE
|
||||
type: string
|
||||
description: The type of the inbox notification.
|
||||
format: enum
|
||||
activityId:
|
||||
type: integer
|
||||
description: Optional. The activity ID associated with this inbox notification.
|
||||
format: int32
|
||||
ListActivitiesResponse:
|
||||
type: object
|
||||
properties:
|
||||
|
|
@ -2357,23 +2296,6 @@ components:
|
|||
items:
|
||||
$ref: '#/components/schemas/IdentityProvider'
|
||||
description: The list of identity providers.
|
||||
ListInboxesResponse:
|
||||
type: object
|
||||
properties:
|
||||
inboxes:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Inbox'
|
||||
description: The list of inboxes.
|
||||
nextPageToken:
|
||||
type: string
|
||||
description: |-
|
||||
A token that can be sent as `page_token` to retrieve the next page.
|
||||
If this field is omitted, there are no subsequent pages.
|
||||
totalSize:
|
||||
type: integer
|
||||
description: The total count of inboxes (may be approximate).
|
||||
format: int32
|
||||
ListMemoAttachmentsResponse:
|
||||
type: object
|
||||
properties:
|
||||
|
|
@ -2462,6 +2384,15 @@ components:
|
|||
type: integer
|
||||
description: The total count of access tokens.
|
||||
format: int32
|
||||
ListUserNotificationsResponse:
|
||||
type: object
|
||||
properties:
|
||||
notifications:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/UserNotification'
|
||||
nextPageToken:
|
||||
type: string
|
||||
ListUserSessionsResponse:
|
||||
type: object
|
||||
properties:
|
||||
|
|
@ -2903,6 +2834,46 @@ components:
|
|||
description: Optional. The expiration timestamp.
|
||||
format: date-time
|
||||
description: User access token message
|
||||
UserNotification:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
readOnly: true
|
||||
type: string
|
||||
description: |-
|
||||
The resource name of the notification.
|
||||
Format: users/{user}/notifications/{notification}
|
||||
sender:
|
||||
readOnly: true
|
||||
type: string
|
||||
description: |-
|
||||
The sender of the notification.
|
||||
Format: users/{user}
|
||||
status:
|
||||
enum:
|
||||
- STATUS_UNSPECIFIED
|
||||
- UNREAD
|
||||
- ARCHIVED
|
||||
type: string
|
||||
description: The status of the notification.
|
||||
format: enum
|
||||
createTime:
|
||||
readOnly: true
|
||||
type: string
|
||||
description: The creation timestamp.
|
||||
format: date-time
|
||||
type:
|
||||
readOnly: true
|
||||
enum:
|
||||
- TYPE_UNSPECIFIED
|
||||
- MEMO_COMMENT
|
||||
type: string
|
||||
description: The type of the notification.
|
||||
format: enum
|
||||
activityId:
|
||||
type: integer
|
||||
description: The activity ID associated with this notification.
|
||||
format: int32
|
||||
UserSession:
|
||||
type: object
|
||||
properties:
|
||||
|
|
@ -3223,7 +3194,6 @@ tags:
|
|||
- name: AttachmentService
|
||||
- name: AuthService
|
||||
- name: IdentityProviderService
|
||||
- name: InboxService
|
||||
- name: MemoService
|
||||
- name: ShortcutService
|
||||
- name: UserService
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ type InboxMessage_Type int32
|
|||
|
||||
const (
|
||||
InboxMessage_TYPE_UNSPECIFIED InboxMessage_Type = 0
|
||||
InboxMessage_MEMO_COMMENT InboxMessage_Type = 1
|
||||
InboxMessage_VERSION_UPDATE InboxMessage_Type = 2
|
||||
// Memo comment notification.
|
||||
InboxMessage_MEMO_COMMENT InboxMessage_Type = 1
|
||||
)
|
||||
|
||||
// Enum value maps for InboxMessage_Type.
|
||||
|
|
@ -34,12 +34,10 @@ var (
|
|||
InboxMessage_Type_name = map[int32]string{
|
||||
0: "TYPE_UNSPECIFIED",
|
||||
1: "MEMO_COMMENT",
|
||||
2: "VERSION_UPDATE",
|
||||
}
|
||||
InboxMessage_Type_value = map[string]int32{
|
||||
"TYPE_UNSPECIFIED": 0,
|
||||
"MEMO_COMMENT": 1,
|
||||
"VERSION_UPDATE": 2,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -71,9 +69,11 @@ func (InboxMessage_Type) EnumDescriptor() ([]byte, []int) {
|
|||
}
|
||||
|
||||
type InboxMessage struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Type InboxMessage_Type `protobuf:"varint,1,opt,name=type,proto3,enum=memos.store.InboxMessage_Type" json:"type,omitempty"`
|
||||
ActivityId *int32 `protobuf:"varint,2,opt,name=activity_id,json=activityId,proto3,oneof" json:"activity_id,omitempty"`
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// The type of the inbox message.
|
||||
Type InboxMessage_Type `protobuf:"varint,1,opt,name=type,proto3,enum=memos.store.InboxMessage_Type" json:"type,omitempty"`
|
||||
// The system-generated unique ID of related activity.
|
||||
ActivityId *int32 `protobuf:"varint,2,opt,name=activity_id,json=activityId,proto3,oneof" json:"activity_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
|
@ -126,15 +126,14 @@ var File_store_inbox_proto protoreflect.FileDescriptor
|
|||
|
||||
const file_store_inbox_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x11store/inbox.proto\x12\vmemos.store\"\xbc\x01\n" +
|
||||
"\x11store/inbox.proto\x12\vmemos.store\"\xa8\x01\n" +
|
||||
"\fInboxMessage\x122\n" +
|
||||
"\x04type\x18\x01 \x01(\x0e2\x1e.memos.store.InboxMessage.TypeR\x04type\x12$\n" +
|
||||
"\vactivity_id\x18\x02 \x01(\x05H\x00R\n" +
|
||||
"activityId\x88\x01\x01\"B\n" +
|
||||
"activityId\x88\x01\x01\".\n" +
|
||||
"\x04Type\x12\x14\n" +
|
||||
"\x10TYPE_UNSPECIFIED\x10\x00\x12\x10\n" +
|
||||
"\fMEMO_COMMENT\x10\x01\x12\x12\n" +
|
||||
"\x0eVERSION_UPDATE\x10\x02B\x0e\n" +
|
||||
"\fMEMO_COMMENT\x10\x01B\x0e\n" +
|
||||
"\f_activity_idB\x95\x01\n" +
|
||||
"\x0fcom.memos.storeB\n" +
|
||||
"InboxProtoP\x01Z)github.com/usememos/memos/proto/gen/store\xa2\x02\x03MSX\xaa\x02\vMemos.Store\xca\x02\vMemos\\Store\xe2\x02\x17Memos\\Store\\GPBMetadata\xea\x02\fMemos::Storeb\x06proto3"
|
||||
|
|
|
|||
|
|
@ -5,11 +5,14 @@ package memos.store;
|
|||
option go_package = "gen/store";
|
||||
|
||||
message InboxMessage {
|
||||
// The type of the inbox message.
|
||||
Type type = 1;
|
||||
// The system-generated unique ID of related activity.
|
||||
optional int32 activity_id = 2;
|
||||
|
||||
enum Type {
|
||||
TYPE_UNSPECIFIED = 0;
|
||||
// Memo comment notification.
|
||||
MEMO_COMMENT = 1;
|
||||
VERSION_UPDATE = 2;
|
||||
}
|
||||
Type type = 1;
|
||||
optional int32 activity_id = 2;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,9 @@ func (s *APIV1Service) GetActivity(ctx context.Context, request *v1pb.GetActivit
|
|||
return activityMessage, nil
|
||||
}
|
||||
|
||||
// convertActivityFromStore converts a storage-layer activity to an API activity.
|
||||
// This handles the mapping between internal activity representation and the public API,
|
||||
// including proper type and level conversions.
|
||||
func (s *APIV1Service) convertActivityFromStore(ctx context.Context, activity *store.Activity) (*v1pb.Activity, error) {
|
||||
payload, err := s.convertActivityPayloadFromStore(ctx, activity.Payload)
|
||||
if err != nil {
|
||||
|
|
@ -98,9 +101,12 @@ func (s *APIV1Service) convertActivityFromStore(ctx context.Context, activity *s
|
|||
}, nil
|
||||
}
|
||||
|
||||
// convertActivityPayloadFromStore converts a storage-layer activity payload to an API payload.
|
||||
// This resolves references (e.g., memo IDs) to resource names for the API.
|
||||
func (s *APIV1Service) convertActivityPayloadFromStore(ctx context.Context, payload *storepb.ActivityPayload) (*v1pb.ActivityPayload, error) {
|
||||
v2Payload := &v1pb.ActivityPayload{}
|
||||
if payload.MemoComment != nil {
|
||||
// Fetch the comment memo
|
||||
memo, err := s.Store.GetMemo(ctx, &store.FindMemo{
|
||||
ID: &payload.MemoComment.MemoId,
|
||||
ExcludeContent: true,
|
||||
|
|
@ -111,6 +117,8 @@ func (s *APIV1Service) convertActivityPayloadFromStore(ctx context.Context, payl
|
|||
if memo == nil {
|
||||
return nil, status.Errorf(codes.NotFound, "memo does not exist")
|
||||
}
|
||||
|
||||
// Fetch the related memo (the one being commented on)
|
||||
relatedMemo, err := s.Store.GetMemo(ctx, &store.FindMemo{
|
||||
ID: &payload.MemoComment.RelatedMemoId,
|
||||
ExcludeContent: true,
|
||||
|
|
@ -118,6 +126,7 @@ func (s *APIV1Service) convertActivityPayloadFromStore(ctx context.Context, payl
|
|||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get related memo: %v", err)
|
||||
}
|
||||
|
||||
v2Payload.Payload = &v1pb.ActivityPayload_MemoComment{
|
||||
MemoComment: &v1pb.ActivityMemoCommentPayload{
|
||||
Memo: fmt.Sprintf("%s%s", MemoNamePrefix, memo.UID),
|
||||
|
|
|
|||
|
|
@ -1,224 +0,0 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
v1pb "github.com/usememos/memos/proto/gen/api/v1"
|
||||
"github.com/usememos/memos/store"
|
||||
)
|
||||
|
||||
func (s *APIV1Service) ListInboxes(ctx context.Context, request *v1pb.ListInboxesRequest) (*v1pb.ListInboxesResponse, error) {
|
||||
// Extract user ID from parent resource name
|
||||
userID, err := ExtractUserIDFromName(request.Parent)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid parent name %q: %v", request.Parent, err)
|
||||
}
|
||||
|
||||
// Get current user for authorization
|
||||
currentUser, err := s.GetCurrentUser(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get current user")
|
||||
}
|
||||
if currentUser == nil {
|
||||
return nil, status.Errorf(codes.Unauthenticated, "user not authenticated")
|
||||
}
|
||||
|
||||
// Check if current user can access the requested user's inboxes
|
||||
if currentUser.ID != userID {
|
||||
// Only allow hosts and admins to access other users' inboxes
|
||||
if currentUser.Role != store.RoleHost && currentUser.Role != store.RoleAdmin {
|
||||
return nil, status.Errorf(codes.PermissionDenied, "cannot access inboxes for user %q", request.Parent)
|
||||
}
|
||||
}
|
||||
|
||||
var limit, offset int
|
||||
if request.PageToken != "" {
|
||||
var pageToken v1pb.PageToken
|
||||
if err := unmarshalPageToken(request.PageToken, &pageToken); err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid page token: %v", err)
|
||||
}
|
||||
limit = int(pageToken.Limit)
|
||||
offset = int(pageToken.Offset)
|
||||
} else {
|
||||
limit = int(request.PageSize)
|
||||
}
|
||||
if limit <= 0 {
|
||||
limit = DefaultPageSize
|
||||
}
|
||||
if limit > MaxPageSize {
|
||||
limit = MaxPageSize
|
||||
}
|
||||
limitPlusOne := limit + 1
|
||||
|
||||
findInbox := &store.FindInbox{
|
||||
ReceiverID: &userID,
|
||||
Limit: &limitPlusOne,
|
||||
Offset: &offset,
|
||||
}
|
||||
|
||||
inboxes, err := s.Store.ListInboxes(ctx, findInbox)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to list inboxes: %v", err)
|
||||
}
|
||||
|
||||
inboxMessages := []*v1pb.Inbox{}
|
||||
nextPageToken := ""
|
||||
if len(inboxes) == limitPlusOne {
|
||||
inboxes = inboxes[:limit]
|
||||
nextPageToken, err = getPageToken(limit, offset+limit)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get next page token: %v", err)
|
||||
}
|
||||
}
|
||||
for _, inbox := range inboxes {
|
||||
inboxMessage := convertInboxFromStore(inbox)
|
||||
if inboxMessage.Type == v1pb.Inbox_TYPE_UNSPECIFIED {
|
||||
continue
|
||||
}
|
||||
inboxMessages = append(inboxMessages, inboxMessage)
|
||||
}
|
||||
|
||||
response := &v1pb.ListInboxesResponse{
|
||||
Inboxes: inboxMessages,
|
||||
NextPageToken: nextPageToken,
|
||||
TotalSize: int32(len(inboxMessages)), // For now, use actual returned count
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *APIV1Service) UpdateInbox(ctx context.Context, request *v1pb.UpdateInboxRequest) (*v1pb.Inbox, error) {
|
||||
if request.UpdateMask == nil || len(request.UpdateMask.Paths) == 0 {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "update mask is required")
|
||||
}
|
||||
|
||||
inboxID, err := ExtractInboxIDFromName(request.Inbox.Name)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid inbox name %q: %v", request.Inbox.Name, err)
|
||||
}
|
||||
|
||||
// Get current user for authorization
|
||||
currentUser, err := s.GetCurrentUser(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get current user")
|
||||
}
|
||||
if currentUser == nil {
|
||||
return nil, status.Errorf(codes.Unauthenticated, "user not authenticated")
|
||||
}
|
||||
|
||||
// Get the existing inbox to verify ownership
|
||||
inboxes, err := s.Store.ListInboxes(ctx, &store.FindInbox{
|
||||
ID: &inboxID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get inbox: %v", err)
|
||||
}
|
||||
if len(inboxes) == 0 {
|
||||
return nil, status.Errorf(codes.NotFound, "inbox %q not found", request.Inbox.Name)
|
||||
}
|
||||
existingInbox := inboxes[0]
|
||||
|
||||
// Check if current user can update this inbox (must be the receiver)
|
||||
if currentUser.ID != existingInbox.ReceiverID {
|
||||
return nil, status.Errorf(codes.PermissionDenied, "cannot update inbox for another user")
|
||||
}
|
||||
|
||||
update := &store.UpdateInbox{
|
||||
ID: inboxID,
|
||||
}
|
||||
for _, field := range request.UpdateMask.Paths {
|
||||
if field == "status" {
|
||||
if request.Inbox.Status == v1pb.Inbox_STATUS_UNSPECIFIED {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "status cannot be unspecified")
|
||||
}
|
||||
update.Status = convertInboxStatusToStore(request.Inbox.Status)
|
||||
} else {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "unsupported field in update mask: %q", field)
|
||||
}
|
||||
}
|
||||
|
||||
inbox, err := s.Store.UpdateInbox(ctx, update)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to update inbox: %v", err)
|
||||
}
|
||||
|
||||
return convertInboxFromStore(inbox), nil
|
||||
}
|
||||
|
||||
func (s *APIV1Service) DeleteInbox(ctx context.Context, request *v1pb.DeleteInboxRequest) (*emptypb.Empty, error) {
|
||||
inboxID, err := ExtractInboxIDFromName(request.Name)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid inbox name %q: %v", request.Name, err)
|
||||
}
|
||||
|
||||
// Get current user for authorization
|
||||
currentUser, err := s.GetCurrentUser(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get current user")
|
||||
}
|
||||
if currentUser == nil {
|
||||
return nil, status.Errorf(codes.Unauthenticated, "user not authenticated")
|
||||
}
|
||||
|
||||
// Get the existing inbox to verify ownership
|
||||
inboxes, err := s.Store.ListInboxes(ctx, &store.FindInbox{
|
||||
ID: &inboxID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get inbox: %v", err)
|
||||
}
|
||||
if len(inboxes) == 0 {
|
||||
return nil, status.Errorf(codes.NotFound, "inbox %q not found", request.Name)
|
||||
}
|
||||
existingInbox := inboxes[0]
|
||||
|
||||
// Check if current user can delete this inbox (must be the receiver)
|
||||
if currentUser.ID != existingInbox.ReceiverID {
|
||||
return nil, status.Errorf(codes.PermissionDenied, "cannot delete inbox for another user")
|
||||
}
|
||||
|
||||
if err := s.Store.DeleteInbox(ctx, &store.DeleteInbox{
|
||||
ID: inboxID,
|
||||
}); err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to delete inbox: %v", err)
|
||||
}
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
func convertInboxFromStore(inbox *store.Inbox) *v1pb.Inbox {
|
||||
return &v1pb.Inbox{
|
||||
Name: fmt.Sprintf("%s%d", InboxNamePrefix, inbox.ID),
|
||||
Sender: fmt.Sprintf("%s%d", UserNamePrefix, inbox.SenderID),
|
||||
Receiver: fmt.Sprintf("%s%d", UserNamePrefix, inbox.ReceiverID),
|
||||
Status: convertInboxStatusFromStore(inbox.Status),
|
||||
CreateTime: timestamppb.New(time.Unix(inbox.CreatedTs, 0)),
|
||||
Type: v1pb.Inbox_Type(inbox.Message.Type),
|
||||
ActivityId: inbox.Message.ActivityId,
|
||||
}
|
||||
}
|
||||
|
||||
func convertInboxStatusFromStore(status store.InboxStatus) v1pb.Inbox_Status {
|
||||
switch status {
|
||||
case store.UNREAD:
|
||||
return v1pb.Inbox_UNREAD
|
||||
case store.ARCHIVED:
|
||||
return v1pb.Inbox_ARCHIVED
|
||||
default:
|
||||
return v1pb.Inbox_STATUS_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func convertInboxStatusToStore(status v1pb.Inbox_Status) store.InboxStatus {
|
||||
switch status {
|
||||
case v1pb.Inbox_ARCHIVED:
|
||||
return store.ARCHIVED
|
||||
default:
|
||||
return store.UNREAD
|
||||
}
|
||||
}
|
||||
|
|
@ -1,559 +0,0 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/fieldmaskpb"
|
||||
|
||||
v1pb "github.com/usememos/memos/proto/gen/api/v1"
|
||||
storepb "github.com/usememos/memos/proto/gen/store"
|
||||
"github.com/usememos/memos/store"
|
||||
)
|
||||
|
||||
func TestListInboxes(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("ListInboxes success", func(t *testing.T) {
|
||||
ts := NewTestService(t)
|
||||
defer ts.Cleanup()
|
||||
|
||||
// Create a user
|
||||
user, err := ts.CreateRegularUser(ctx, "testuser")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set user context
|
||||
userCtx := ts.CreateUserContext(ctx, user.ID)
|
||||
|
||||
// List inboxes (should be empty initially)
|
||||
req := &v1pb.ListInboxesRequest{
|
||||
Parent: fmt.Sprintf("users/%d", user.ID),
|
||||
}
|
||||
|
||||
resp, err := ts.Service.ListInboxes(userCtx, req)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
require.Empty(t, resp.Inboxes)
|
||||
require.Equal(t, int32(0), resp.TotalSize)
|
||||
})
|
||||
|
||||
t.Run("ListInboxes with pagination", func(t *testing.T) {
|
||||
ts := NewTestService(t)
|
||||
defer ts.Cleanup()
|
||||
|
||||
// Create a user
|
||||
user, err := ts.CreateRegularUser(ctx, "testuser")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create some inbox entries
|
||||
const systemBotID int32 = 0
|
||||
for i := 0; i < 3; i++ {
|
||||
_, err := ts.Store.CreateInbox(ctx, &store.Inbox{
|
||||
SenderID: systemBotID,
|
||||
ReceiverID: user.ID,
|
||||
Status: store.UNREAD,
|
||||
Message: &storepb.InboxMessage{
|
||||
Type: storepb.InboxMessage_MEMO_COMMENT,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Set user context
|
||||
userCtx := ts.CreateUserContext(ctx, user.ID)
|
||||
|
||||
// List inboxes with page size limit
|
||||
req := &v1pb.ListInboxesRequest{
|
||||
Parent: fmt.Sprintf("users/%d", user.ID),
|
||||
PageSize: 2,
|
||||
}
|
||||
|
||||
resp, err := ts.Service.ListInboxes(userCtx, req)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
require.Equal(t, 2, len(resp.Inboxes))
|
||||
require.NotEmpty(t, resp.NextPageToken)
|
||||
})
|
||||
|
||||
t.Run("ListInboxes permission denied for different user", func(t *testing.T) {
|
||||
ts := NewTestService(t)
|
||||
defer ts.Cleanup()
|
||||
|
||||
// Create two users
|
||||
user1, err := ts.CreateRegularUser(ctx, "user1")
|
||||
require.NoError(t, err)
|
||||
user2, err := ts.CreateRegularUser(ctx, "user2")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set user1 context but try to list user2's inboxes
|
||||
userCtx := ts.CreateUserContext(ctx, user1.ID)
|
||||
|
||||
req := &v1pb.ListInboxesRequest{
|
||||
Parent: fmt.Sprintf("users/%d", user2.ID),
|
||||
}
|
||||
|
||||
_, err = ts.Service.ListInboxes(userCtx, req)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "cannot access inboxes")
|
||||
})
|
||||
|
||||
t.Run("ListInboxes host can access other users' inboxes", func(t *testing.T) {
|
||||
ts := NewTestService(t)
|
||||
defer ts.Cleanup()
|
||||
|
||||
// Create a host user and a regular user
|
||||
hostUser, err := ts.CreateHostUser(ctx, "hostuser")
|
||||
require.NoError(t, err)
|
||||
regularUser, err := ts.CreateRegularUser(ctx, "regularuser")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create an inbox for the regular user
|
||||
const systemBotID int32 = 0
|
||||
_, err = ts.Store.CreateInbox(ctx, &store.Inbox{
|
||||
SenderID: systemBotID,
|
||||
ReceiverID: regularUser.ID,
|
||||
Status: store.UNREAD,
|
||||
Message: &storepb.InboxMessage{
|
||||
Type: storepb.InboxMessage_MEMO_COMMENT,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set host user context and try to list regular user's inboxes
|
||||
hostCtx := ts.CreateUserContext(ctx, hostUser.ID)
|
||||
|
||||
req := &v1pb.ListInboxesRequest{
|
||||
Parent: fmt.Sprintf("users/%d", regularUser.ID),
|
||||
}
|
||||
|
||||
resp, err := ts.Service.ListInboxes(hostCtx, req)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
require.Equal(t, 1, len(resp.Inboxes))
|
||||
})
|
||||
|
||||
t.Run("ListInboxes invalid parent format", func(t *testing.T) {
|
||||
ts := NewTestService(t)
|
||||
defer ts.Cleanup()
|
||||
|
||||
// Create a user
|
||||
user, err := ts.CreateRegularUser(ctx, "testuser")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set user context
|
||||
userCtx := ts.CreateUserContext(ctx, user.ID)
|
||||
|
||||
req := &v1pb.ListInboxesRequest{
|
||||
Parent: "invalid-parent-format",
|
||||
}
|
||||
|
||||
_, err = ts.Service.ListInboxes(userCtx, req)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "invalid parent name")
|
||||
})
|
||||
|
||||
t.Run("ListInboxes unauthenticated", func(t *testing.T) {
|
||||
ts := NewTestService(t)
|
||||
defer ts.Cleanup()
|
||||
|
||||
req := &v1pb.ListInboxesRequest{
|
||||
Parent: "users/1",
|
||||
}
|
||||
|
||||
_, err := ts.Service.ListInboxes(ctx, req)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "user not authenticated")
|
||||
})
|
||||
}
|
||||
|
||||
func TestUpdateInbox(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("UpdateInbox success", func(t *testing.T) {
|
||||
ts := NewTestService(t)
|
||||
defer ts.Cleanup()
|
||||
|
||||
// Create a user
|
||||
user, err := ts.CreateRegularUser(ctx, "testuser")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create an inbox entry
|
||||
const systemBotID int32 = 0
|
||||
inbox, err := ts.Store.CreateInbox(ctx, &store.Inbox{
|
||||
SenderID: systemBotID,
|
||||
ReceiverID: user.ID,
|
||||
Status: store.UNREAD,
|
||||
Message: &storepb.InboxMessage{
|
||||
Type: storepb.InboxMessage_MEMO_COMMENT,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set user context
|
||||
userCtx := ts.CreateUserContext(ctx, user.ID)
|
||||
|
||||
// Update inbox status
|
||||
req := &v1pb.UpdateInboxRequest{
|
||||
Inbox: &v1pb.Inbox{
|
||||
Name: fmt.Sprintf("inboxes/%d", inbox.ID),
|
||||
Status: v1pb.Inbox_ARCHIVED,
|
||||
},
|
||||
UpdateMask: &fieldmaskpb.FieldMask{
|
||||
Paths: []string{"status"},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := ts.Service.UpdateInbox(userCtx, req)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
require.Equal(t, v1pb.Inbox_ARCHIVED, resp.Status)
|
||||
})
|
||||
|
||||
t.Run("UpdateInbox permission denied for different user", func(t *testing.T) {
|
||||
ts := NewTestService(t)
|
||||
defer ts.Cleanup()
|
||||
|
||||
// Create two users
|
||||
user1, err := ts.CreateRegularUser(ctx, "user1")
|
||||
require.NoError(t, err)
|
||||
user2, err := ts.CreateRegularUser(ctx, "user2")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create an inbox entry for user2
|
||||
const systemBotID int32 = 0
|
||||
inbox, err := ts.Store.CreateInbox(ctx, &store.Inbox{
|
||||
SenderID: systemBotID,
|
||||
ReceiverID: user2.ID,
|
||||
Status: store.UNREAD,
|
||||
Message: &storepb.InboxMessage{
|
||||
Type: storepb.InboxMessage_MEMO_COMMENT,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set user1 context but try to update user2's inbox
|
||||
userCtx := ts.CreateUserContext(ctx, user1.ID)
|
||||
|
||||
req := &v1pb.UpdateInboxRequest{
|
||||
Inbox: &v1pb.Inbox{
|
||||
Name: fmt.Sprintf("inboxes/%d", inbox.ID),
|
||||
Status: v1pb.Inbox_ARCHIVED,
|
||||
},
|
||||
UpdateMask: &fieldmaskpb.FieldMask{
|
||||
Paths: []string{"status"},
|
||||
},
|
||||
}
|
||||
|
||||
_, err = ts.Service.UpdateInbox(userCtx, req)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "cannot update inbox")
|
||||
})
|
||||
|
||||
t.Run("UpdateInbox missing update mask", func(t *testing.T) {
|
||||
ts := NewTestService(t)
|
||||
defer ts.Cleanup()
|
||||
|
||||
// Create a user
|
||||
user, err := ts.CreateRegularUser(ctx, "testuser")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set user context
|
||||
userCtx := ts.CreateUserContext(ctx, user.ID)
|
||||
|
||||
req := &v1pb.UpdateInboxRequest{
|
||||
Inbox: &v1pb.Inbox{
|
||||
Name: "inboxes/1",
|
||||
Status: v1pb.Inbox_ARCHIVED,
|
||||
},
|
||||
}
|
||||
|
||||
_, err = ts.Service.UpdateInbox(userCtx, req)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "update mask is required")
|
||||
})
|
||||
|
||||
t.Run("UpdateInbox invalid name format", func(t *testing.T) {
|
||||
ts := NewTestService(t)
|
||||
defer ts.Cleanup()
|
||||
|
||||
// Create a user
|
||||
user, err := ts.CreateRegularUser(ctx, "testuser")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set user context
|
||||
userCtx := ts.CreateUserContext(ctx, user.ID)
|
||||
|
||||
req := &v1pb.UpdateInboxRequest{
|
||||
Inbox: &v1pb.Inbox{
|
||||
Name: "invalid-inbox-name",
|
||||
Status: v1pb.Inbox_ARCHIVED,
|
||||
},
|
||||
UpdateMask: &fieldmaskpb.FieldMask{
|
||||
Paths: []string{"status"},
|
||||
},
|
||||
}
|
||||
|
||||
_, err = ts.Service.UpdateInbox(userCtx, req)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "invalid inbox name")
|
||||
})
|
||||
|
||||
t.Run("UpdateInbox not found", func(t *testing.T) {
|
||||
ts := NewTestService(t)
|
||||
defer ts.Cleanup()
|
||||
|
||||
// Create a user
|
||||
user, err := ts.CreateRegularUser(ctx, "testuser")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set user context
|
||||
userCtx := ts.CreateUserContext(ctx, user.ID)
|
||||
|
||||
req := &v1pb.UpdateInboxRequest{
|
||||
Inbox: &v1pb.Inbox{
|
||||
Name: "inboxes/99999", // Non-existent inbox
|
||||
Status: v1pb.Inbox_ARCHIVED,
|
||||
},
|
||||
UpdateMask: &fieldmaskpb.FieldMask{
|
||||
Paths: []string{"status"},
|
||||
},
|
||||
}
|
||||
|
||||
_, err = ts.Service.UpdateInbox(userCtx, req)
|
||||
require.Error(t, err)
|
||||
st, ok := status.FromError(err)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, codes.NotFound, st.Code())
|
||||
})
|
||||
|
||||
t.Run("UpdateInbox unsupported field", func(t *testing.T) {
|
||||
ts := NewTestService(t)
|
||||
defer ts.Cleanup()
|
||||
|
||||
// Create a user
|
||||
user, err := ts.CreateRegularUser(ctx, "testuser")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create an inbox entry
|
||||
const systemBotID int32 = 0
|
||||
inbox, err := ts.Store.CreateInbox(ctx, &store.Inbox{
|
||||
SenderID: systemBotID,
|
||||
ReceiverID: user.ID,
|
||||
Status: store.UNREAD,
|
||||
Message: &storepb.InboxMessage{
|
||||
Type: storepb.InboxMessage_MEMO_COMMENT,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set user context
|
||||
userCtx := ts.CreateUserContext(ctx, user.ID)
|
||||
|
||||
req := &v1pb.UpdateInboxRequest{
|
||||
Inbox: &v1pb.Inbox{
|
||||
Name: fmt.Sprintf("inboxes/%d", inbox.ID),
|
||||
Status: v1pb.Inbox_ARCHIVED,
|
||||
},
|
||||
UpdateMask: &fieldmaskpb.FieldMask{
|
||||
Paths: []string{"unsupported_field"},
|
||||
},
|
||||
}
|
||||
|
||||
_, err = ts.Service.UpdateInbox(userCtx, req)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "unsupported field")
|
||||
})
|
||||
}
|
||||
|
||||
func TestDeleteInbox(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("DeleteInbox success", func(t *testing.T) {
|
||||
ts := NewTestService(t)
|
||||
defer ts.Cleanup()
|
||||
|
||||
// Create a user
|
||||
user, err := ts.CreateRegularUser(ctx, "testuser")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create an inbox entry
|
||||
const systemBotID int32 = 0
|
||||
inbox, err := ts.Store.CreateInbox(ctx, &store.Inbox{
|
||||
SenderID: systemBotID,
|
||||
ReceiverID: user.ID,
|
||||
Status: store.UNREAD,
|
||||
Message: &storepb.InboxMessage{
|
||||
Type: storepb.InboxMessage_MEMO_COMMENT,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set user context
|
||||
userCtx := ts.CreateUserContext(ctx, user.ID)
|
||||
|
||||
// Delete inbox
|
||||
req := &v1pb.DeleteInboxRequest{
|
||||
Name: fmt.Sprintf("inboxes/%d", inbox.ID),
|
||||
}
|
||||
|
||||
_, err = ts.Service.DeleteInbox(userCtx, req)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify inbox is deleted
|
||||
inboxes, err := ts.Store.ListInboxes(ctx, &store.FindInbox{
|
||||
ReceiverID: &user.ID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(inboxes))
|
||||
})
|
||||
|
||||
t.Run("DeleteInbox permission denied for different user", func(t *testing.T) {
|
||||
ts := NewTestService(t)
|
||||
defer ts.Cleanup()
|
||||
|
||||
// Create two users
|
||||
user1, err := ts.CreateRegularUser(ctx, "user1")
|
||||
require.NoError(t, err)
|
||||
user2, err := ts.CreateRegularUser(ctx, "user2")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create an inbox entry for user2
|
||||
const systemBotID int32 = 0
|
||||
inbox, err := ts.Store.CreateInbox(ctx, &store.Inbox{
|
||||
SenderID: systemBotID,
|
||||
ReceiverID: user2.ID,
|
||||
Status: store.UNREAD,
|
||||
Message: &storepb.InboxMessage{
|
||||
Type: storepb.InboxMessage_MEMO_COMMENT,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set user1 context but try to delete user2's inbox
|
||||
userCtx := ts.CreateUserContext(ctx, user1.ID)
|
||||
|
||||
req := &v1pb.DeleteInboxRequest{
|
||||
Name: fmt.Sprintf("inboxes/%d", inbox.ID),
|
||||
}
|
||||
|
||||
_, err = ts.Service.DeleteInbox(userCtx, req)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "cannot delete inbox")
|
||||
})
|
||||
|
||||
t.Run("DeleteInbox invalid name format", func(t *testing.T) {
|
||||
ts := NewTestService(t)
|
||||
defer ts.Cleanup()
|
||||
|
||||
// Create a user
|
||||
user, err := ts.CreateRegularUser(ctx, "testuser")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set user context
|
||||
userCtx := ts.CreateUserContext(ctx, user.ID)
|
||||
|
||||
req := &v1pb.DeleteInboxRequest{
|
||||
Name: "invalid-inbox-name",
|
||||
}
|
||||
|
||||
_, err = ts.Service.DeleteInbox(userCtx, req)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "invalid inbox name")
|
||||
})
|
||||
|
||||
t.Run("DeleteInbox not found", func(t *testing.T) {
|
||||
ts := NewTestService(t)
|
||||
defer ts.Cleanup()
|
||||
|
||||
// Create a user
|
||||
user, err := ts.CreateRegularUser(ctx, "testuser")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set user context
|
||||
userCtx := ts.CreateUserContext(ctx, user.ID)
|
||||
|
||||
req := &v1pb.DeleteInboxRequest{
|
||||
Name: "inboxes/99999", // Non-existent inbox
|
||||
}
|
||||
|
||||
_, err = ts.Service.DeleteInbox(userCtx, req)
|
||||
require.Error(t, err)
|
||||
st, ok := status.FromError(err)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, codes.NotFound, st.Code())
|
||||
})
|
||||
}
|
||||
|
||||
func TestInboxCRUDComplete(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
t.Run("Complete CRUD lifecycle", func(t *testing.T) {
|
||||
ts := NewTestService(t)
|
||||
defer ts.Cleanup()
|
||||
|
||||
// Create a user
|
||||
user, err := ts.CreateRegularUser(ctx, "testuser")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create an inbox entry directly in store
|
||||
const systemBotID int32 = 0
|
||||
inbox, err := ts.Store.CreateInbox(ctx, &store.Inbox{
|
||||
SenderID: systemBotID,
|
||||
ReceiverID: user.ID,
|
||||
Status: store.UNREAD,
|
||||
Message: &storepb.InboxMessage{
|
||||
Type: storepb.InboxMessage_MEMO_COMMENT,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set user context
|
||||
userCtx := ts.CreateUserContext(ctx, user.ID)
|
||||
|
||||
// 1. List inboxes - should have 1
|
||||
listReq := &v1pb.ListInboxesRequest{
|
||||
Parent: fmt.Sprintf("users/%d", user.ID),
|
||||
}
|
||||
listResp, err := ts.Service.ListInboxes(userCtx, listReq)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(listResp.Inboxes))
|
||||
require.Equal(t, v1pb.Inbox_UNREAD, listResp.Inboxes[0].Status)
|
||||
|
||||
// 2. Update inbox status to ARCHIVED
|
||||
updateReq := &v1pb.UpdateInboxRequest{
|
||||
Inbox: &v1pb.Inbox{
|
||||
Name: fmt.Sprintf("inboxes/%d", inbox.ID),
|
||||
Status: v1pb.Inbox_ARCHIVED,
|
||||
},
|
||||
UpdateMask: &fieldmaskpb.FieldMask{
|
||||
Paths: []string{"status"},
|
||||
},
|
||||
}
|
||||
updateResp, err := ts.Service.UpdateInbox(userCtx, updateReq)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, v1pb.Inbox_ARCHIVED, updateResp.Status)
|
||||
|
||||
// 3. List inboxes again - should still have 1 but ARCHIVED
|
||||
listResp, err = ts.Service.ListInboxes(userCtx, listReq)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(listResp.Inboxes))
|
||||
require.Equal(t, v1pb.Inbox_ARCHIVED, listResp.Inboxes[0].Status)
|
||||
|
||||
// 4. Delete inbox
|
||||
deleteReq := &v1pb.DeleteInboxRequest{
|
||||
Name: fmt.Sprintf("inboxes/%d", inbox.ID),
|
||||
}
|
||||
_, err = ts.Service.DeleteInbox(userCtx, deleteReq)
|
||||
require.NoError(t, err)
|
||||
|
||||
// 5. List inboxes - should be empty
|
||||
listResp, err = ts.Service.ListInboxes(userCtx, listReq)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(listResp.Inboxes))
|
||||
require.Equal(t, int32(0), listResp.TotalSize)
|
||||
})
|
||||
}
|
||||
|
|
@ -1552,3 +1552,201 @@ func extractUsernameFromComparison(left, right ast.Expr) (string, bool) {
|
|||
|
||||
return str, true
|
||||
}
|
||||
|
||||
// ListUserNotifications lists all notifications for a user.
|
||||
// Notifications are backed by the inbox storage layer and represent activities
|
||||
// that require user attention (e.g., memo comments).
|
||||
func (s *APIV1Service) ListUserNotifications(ctx context.Context, request *v1pb.ListUserNotificationsRequest) (*v1pb.ListUserNotificationsResponse, error) {
|
||||
userID, err := ExtractUserIDFromName(request.Parent)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid user name: %v", err)
|
||||
}
|
||||
|
||||
// Verify the requesting user has permission to view these notifications
|
||||
currentUser, err := s.GetCurrentUser(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get current user: %v", err)
|
||||
}
|
||||
if currentUser.ID != userID {
|
||||
return nil, status.Errorf(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
|
||||
// Fetch inbox items from storage
|
||||
inboxes, err := s.Store.ListInboxes(ctx, &store.FindInbox{
|
||||
ReceiverID: &userID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to list inboxes: %v", err)
|
||||
}
|
||||
|
||||
// Convert storage layer inboxes to API notifications
|
||||
notifications := []*v1pb.UserNotification{}
|
||||
for _, inbox := range inboxes {
|
||||
notification, err := s.convertInboxToUserNotification(ctx, inbox)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to convert inbox: %v", err)
|
||||
}
|
||||
notifications = append(notifications, notification)
|
||||
}
|
||||
|
||||
return &v1pb.ListUserNotificationsResponse{
|
||||
Notifications: notifications,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateUserNotification updates a notification's status (e.g., marking as read/archived).
|
||||
// Only the notification owner can update their notifications.
|
||||
func (s *APIV1Service) UpdateUserNotification(ctx context.Context, request *v1pb.UpdateUserNotificationRequest) (*v1pb.UserNotification, error) {
|
||||
if request.Notification == nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "notification is required")
|
||||
}
|
||||
|
||||
notificationID, err := ExtractNotificationIDFromName(request.Notification.Name)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid notification name: %v", err)
|
||||
}
|
||||
|
||||
currentUser, err := s.GetCurrentUser(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get current user: %v", err)
|
||||
}
|
||||
|
||||
// Verify ownership before updating
|
||||
inboxes, err := s.Store.ListInboxes(ctx, &store.FindInbox{
|
||||
ID: ¬ificationID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get inbox: %v", err)
|
||||
}
|
||||
if len(inboxes) == 0 {
|
||||
return nil, status.Errorf(codes.NotFound, "notification not found")
|
||||
}
|
||||
inbox := inboxes[0]
|
||||
if inbox.ReceiverID != currentUser.ID {
|
||||
return nil, status.Errorf(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
|
||||
// Build update request based on field mask
|
||||
update := &store.UpdateInbox{
|
||||
ID: notificationID,
|
||||
}
|
||||
|
||||
for _, path := range request.UpdateMask.Paths {
|
||||
switch path {
|
||||
case "status":
|
||||
// Convert API status enum to storage enum
|
||||
var inboxStatus store.InboxStatus
|
||||
switch request.Notification.Status {
|
||||
case v1pb.UserNotification_UNREAD:
|
||||
inboxStatus = store.UNREAD
|
||||
case v1pb.UserNotification_ARCHIVED:
|
||||
inboxStatus = store.ARCHIVED
|
||||
default:
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid status")
|
||||
}
|
||||
update.Status = inboxStatus
|
||||
}
|
||||
}
|
||||
|
||||
updatedInbox, err := s.Store.UpdateInbox(ctx, update)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to update inbox: %v", err)
|
||||
}
|
||||
|
||||
notification, err := s.convertInboxToUserNotification(ctx, updatedInbox)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to convert inbox: %v", err)
|
||||
}
|
||||
|
||||
return notification, nil
|
||||
}
|
||||
|
||||
// DeleteUserNotification permanently deletes a notification.
|
||||
// Only the notification owner can delete their notifications.
|
||||
func (s *APIV1Service) DeleteUserNotification(ctx context.Context, request *v1pb.DeleteUserNotificationRequest) (*emptypb.Empty, error) {
|
||||
notificationID, err := ExtractNotificationIDFromName(request.Name)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid notification name: %v", err)
|
||||
}
|
||||
|
||||
currentUser, err := s.GetCurrentUser(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get current user: %v", err)
|
||||
}
|
||||
|
||||
// Verify ownership before deletion
|
||||
inboxes, err := s.Store.ListInboxes(ctx, &store.FindInbox{
|
||||
ID: ¬ificationID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get inbox: %v", err)
|
||||
}
|
||||
if len(inboxes) == 0 {
|
||||
return nil, status.Errorf(codes.NotFound, "notification not found")
|
||||
}
|
||||
inbox := inboxes[0]
|
||||
if inbox.ReceiverID != currentUser.ID {
|
||||
return nil, status.Errorf(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
|
||||
if err := s.Store.DeleteInbox(ctx, &store.DeleteInbox{
|
||||
ID: notificationID,
|
||||
}); err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to delete inbox: %v", err)
|
||||
}
|
||||
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
// convertInboxToUserNotification converts a storage-layer inbox to an API notification.
|
||||
// This handles the mapping between the internal inbox representation and the public API.
|
||||
func (s *APIV1Service) convertInboxToUserNotification(ctx context.Context, inbox *store.Inbox) (*v1pb.UserNotification, error) {
|
||||
notification := &v1pb.UserNotification{
|
||||
Name: fmt.Sprintf("users/%d/notifications/%d", inbox.ReceiverID, inbox.ID),
|
||||
Sender: fmt.Sprintf("%s%d", UserNamePrefix, inbox.SenderID),
|
||||
CreateTime: timestamppb.New(time.Unix(inbox.CreatedTs, 0)),
|
||||
}
|
||||
|
||||
// Convert status from storage enum to API enum
|
||||
switch inbox.Status {
|
||||
case store.UNREAD:
|
||||
notification.Status = v1pb.UserNotification_UNREAD
|
||||
case store.ARCHIVED:
|
||||
notification.Status = v1pb.UserNotification_ARCHIVED
|
||||
default:
|
||||
notification.Status = v1pb.UserNotification_STATUS_UNSPECIFIED
|
||||
}
|
||||
|
||||
// Extract notification type and activity ID from inbox message
|
||||
if inbox.Message != nil {
|
||||
switch inbox.Message.Type {
|
||||
case storepb.InboxMessage_MEMO_COMMENT:
|
||||
notification.Type = v1pb.UserNotification_MEMO_COMMENT
|
||||
default:
|
||||
notification.Type = v1pb.UserNotification_TYPE_UNSPECIFIED
|
||||
}
|
||||
|
||||
if inbox.Message.ActivityId != nil {
|
||||
notification.ActivityId = inbox.Message.ActivityId
|
||||
}
|
||||
}
|
||||
|
||||
return notification, nil
|
||||
}
|
||||
|
||||
// ExtractNotificationIDFromName extracts the notification ID from a resource name.
|
||||
// Expected format: users/{user_id}/notifications/{notification_id}
|
||||
func ExtractNotificationIDFromName(name string) (int32, error) {
|
||||
pattern := regexp.MustCompile(`^users/(\d+)/notifications/(\d+)$`)
|
||||
matches := pattern.FindStringSubmatch(name)
|
||||
if len(matches) != 3 {
|
||||
return 0, errors.Errorf("invalid notification name: %s", name)
|
||||
}
|
||||
|
||||
id, err := strconv.Atoi(matches[2])
|
||||
if err != nil {
|
||||
return 0, errors.Errorf("invalid notification id: %s", matches[2])
|
||||
}
|
||||
|
||||
return int32(id), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ type APIV1Service struct {
|
|||
v1pb.UnimplementedMemoServiceServer
|
||||
v1pb.UnimplementedAttachmentServiceServer
|
||||
v1pb.UnimplementedShortcutServiceServer
|
||||
v1pb.UnimplementedInboxServiceServer
|
||||
v1pb.UnimplementedActivityServiceServer
|
||||
v1pb.UnimplementedIdentityProviderServiceServer
|
||||
|
||||
|
|
@ -60,7 +59,6 @@ func NewAPIV1Service(secret string, profile *profile.Profile, store *store.Store
|
|||
v1pb.RegisterMemoServiceServer(grpcServer, apiv1Service)
|
||||
v1pb.RegisterAttachmentServiceServer(grpcServer, apiv1Service)
|
||||
v1pb.RegisterShortcutServiceServer(grpcServer, apiv1Service)
|
||||
v1pb.RegisterInboxServiceServer(grpcServer, apiv1Service)
|
||||
v1pb.RegisterActivityServiceServer(grpcServer, apiv1Service)
|
||||
v1pb.RegisterIdentityProviderServiceServer(grpcServer, apiv1Service)
|
||||
reflection.Register(grpcServer)
|
||||
|
|
@ -107,9 +105,6 @@ func (s *APIV1Service) RegisterGateway(ctx context.Context, echoServer *echo.Ech
|
|||
if err := v1pb.RegisterShortcutServiceHandler(ctx, gwMux, conn); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1pb.RegisterInboxServiceHandler(ctx, gwMux, conn); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1pb.RegisterActivityServiceHandler(ctx, gwMux, conn); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,13 @@ import (
|
|||
storepb "github.com/usememos/memos/proto/gen/store"
|
||||
)
|
||||
|
||||
// InboxStatus is the status for an inbox.
|
||||
// InboxStatus represents the status of an inbox notification.
|
||||
type InboxStatus string
|
||||
|
||||
const (
|
||||
UNREAD InboxStatus = "UNREAD"
|
||||
// UNREAD indicates the notification has not been read by the user.
|
||||
UNREAD InboxStatus = "UNREAD"
|
||||
// ARCHIVED indicates the notification has been archived/dismissed by the user.
|
||||
ARCHIVED InboxStatus = "ARCHIVED"
|
||||
)
|
||||
|
||||
|
|
@ -18,20 +20,24 @@ func (s InboxStatus) String() string {
|
|||
return string(s)
|
||||
}
|
||||
|
||||
// Inbox represents a notification in a user's inbox.
|
||||
// It connects activities to users who should be notified.
|
||||
type Inbox struct {
|
||||
ID int32
|
||||
CreatedTs int64
|
||||
SenderID int32
|
||||
ReceiverID int32
|
||||
Status InboxStatus
|
||||
Message *storepb.InboxMessage
|
||||
SenderID int32 // The user who triggered the notification
|
||||
ReceiverID int32 // The user who receives the notification
|
||||
Status InboxStatus // Current status (unread/archived)
|
||||
Message *storepb.InboxMessage // The notification message content
|
||||
}
|
||||
|
||||
// UpdateInbox contains fields that can be updated for an inbox item.
|
||||
type UpdateInbox struct {
|
||||
ID int32
|
||||
Status InboxStatus
|
||||
}
|
||||
|
||||
// FindInbox specifies filter criteria for querying inbox items.
|
||||
type FindInbox struct {
|
||||
ID *int32
|
||||
SenderID *int32
|
||||
|
|
@ -43,22 +49,27 @@ type FindInbox struct {
|
|||
Offset *int
|
||||
}
|
||||
|
||||
// DeleteInbox specifies which inbox item to delete.
|
||||
type DeleteInbox struct {
|
||||
ID int32
|
||||
}
|
||||
|
||||
// CreateInbox creates a new inbox notification.
|
||||
func (s *Store) CreateInbox(ctx context.Context, create *Inbox) (*Inbox, error) {
|
||||
return s.driver.CreateInbox(ctx, create)
|
||||
}
|
||||
|
||||
// ListInboxes retrieves inbox items matching the filter criteria.
|
||||
func (s *Store) ListInboxes(ctx context.Context, find *FindInbox) ([]*Inbox, error) {
|
||||
return s.driver.ListInboxes(ctx, find)
|
||||
}
|
||||
|
||||
// UpdateInbox updates an existing inbox item.
|
||||
func (s *Store) UpdateInbox(ctx context.Context, update *UpdateInbox) (*Inbox, error) {
|
||||
return s.driver.UpdateInbox(ctx, update)
|
||||
}
|
||||
|
||||
// DeleteInbox permanently removes an inbox item.
|
||||
func (s *Store) DeleteInbox(ctx context.Context, delete *DeleteInbox) error {
|
||||
return s.driver.DeleteInbox(ctx, delete)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,39 +1,39 @@
|
|||
import { InboxIcon, LoaderIcon, MessageCircleIcon, TrashIcon } from "lucide-react";
|
||||
import { CheckIcon, MessageCircleIcon, TrashIcon, XIcon } from "lucide-react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import UserAvatar from "@/components/UserAvatar";
|
||||
import { activityServiceClient } from "@/grpcweb";
|
||||
import useAsyncEffect from "@/hooks/useAsyncEffect";
|
||||
import useNavigateTo from "@/hooks/useNavigateTo";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { memoStore, userStore } from "@/store";
|
||||
import { activityNamePrefix } from "@/store/common";
|
||||
import { Inbox, Inbox_Status } from "@/types/proto/api/v1/inbox_service";
|
||||
import { Memo } from "@/types/proto/api/v1/memo_service";
|
||||
import { User } from "@/types/proto/api/v1/user_service";
|
||||
import { User, UserNotification, UserNotification_Status } from "@/types/proto/api/v1/user_service";
|
||||
import { useTranslate } from "@/utils/i18n";
|
||||
|
||||
interface Props {
|
||||
inbox: Inbox;
|
||||
notification: UserNotification;
|
||||
}
|
||||
|
||||
const MemoCommentMessage = observer(({ inbox }: Props) => {
|
||||
const MemoCommentMessage = observer(({ notification }: Props) => {
|
||||
const t = useTranslate();
|
||||
const navigateTo = useNavigateTo();
|
||||
const [relatedMemo, setRelatedMemo] = useState<Memo | undefined>(undefined);
|
||||
const [commentMemo, setCommentMemo] = useState<Memo | undefined>(undefined);
|
||||
const [sender, setSender] = useState<User | undefined>(undefined);
|
||||
const [initialized, setInitialized] = useState<boolean>(false);
|
||||
const [hasError, setHasError] = useState<boolean>(false);
|
||||
|
||||
useAsyncEffect(async () => {
|
||||
if (!inbox.activityId) {
|
||||
if (!notification.activityId) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const activity = await activityServiceClient.getActivity({
|
||||
name: `${activityNamePrefix}${inbox.activityId}`,
|
||||
name: `${activityNamePrefix}${notification.activityId}`,
|
||||
});
|
||||
|
||||
if (activity.payload?.memoComment) {
|
||||
|
|
@ -42,7 +42,14 @@ const MemoCommentMessage = observer(({ inbox }: Props) => {
|
|||
skipStore: true,
|
||||
});
|
||||
setRelatedMemo(memo);
|
||||
const sender = await userStore.getOrFetchUserByName(inbox.sender);
|
||||
|
||||
// Fetch the comment memo
|
||||
const comment = await memoStore.getOrFetchMemoByName(memoCommentPayload.memo, {
|
||||
skipStore: true,
|
||||
});
|
||||
setCommentMemo(comment);
|
||||
|
||||
const sender = await userStore.getOrFetchUserByName(notification.sender);
|
||||
setSender(sender);
|
||||
setInitialized(true);
|
||||
}
|
||||
|
|
@ -51,7 +58,7 @@ const MemoCommentMessage = observer(({ inbox }: Props) => {
|
|||
setHasError(true);
|
||||
return;
|
||||
}
|
||||
}, [inbox.activityId]);
|
||||
}, [notification.activityId]);
|
||||
|
||||
const handleNavigateToMemo = async () => {
|
||||
if (!relatedMemo) {
|
||||
|
|
@ -59,16 +66,16 @@ const MemoCommentMessage = observer(({ inbox }: Props) => {
|
|||
}
|
||||
|
||||
navigateTo(`/${relatedMemo.name}`);
|
||||
if (inbox.status === Inbox_Status.UNREAD) {
|
||||
if (notification.status === UserNotification_Status.UNREAD) {
|
||||
handleArchiveMessage(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleArchiveMessage = async (silence = false) => {
|
||||
await userStore.updateInbox(
|
||||
await userStore.updateNotification(
|
||||
{
|
||||
name: inbox.name,
|
||||
status: Inbox_Status.ARCHIVED,
|
||||
name: notification.name,
|
||||
status: UserNotification_Status.ARCHIVED,
|
||||
},
|
||||
["status"],
|
||||
);
|
||||
|
|
@ -78,104 +85,120 @@ const MemoCommentMessage = observer(({ inbox }: Props) => {
|
|||
};
|
||||
|
||||
const handleDeleteMessage = async () => {
|
||||
await userStore.deleteInbox(inbox.name);
|
||||
await userStore.deleteNotification(notification.name);
|
||||
toast.success(t("message.deleted-successfully"));
|
||||
};
|
||||
|
||||
const deleteButton = () => (
|
||||
<>
|
||||
<div>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<TrashIcon
|
||||
className="w-4 h-auto cursor-pointer text-muted-foreground hover:text-primary"
|
||||
onClick={() => handleDeleteMessage()}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common.delete")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
if (!initialized && !hasError) {
|
||||
return (
|
||||
<div className="w-full px-4 py-3.5 border-b border-border last:border-b-0 bg-muted/20 animate-pulse">
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="w-9 h-9 rounded-full bg-muted/60 shrink-0" />
|
||||
<div className="flex-1 space-y-2.5">
|
||||
<div className="h-3.5 bg-muted/60 rounded w-2/5" />
|
||||
<div className="h-16 bg-muted/40 rounded-md" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
const archiveButton = () => (
|
||||
<>
|
||||
<div>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<InboxIcon
|
||||
className="w-4 h-auto cursor-pointer text-muted-foreground hover:text-primary"
|
||||
onClick={() => handleArchiveMessage()}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{t("common.archive")}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
if (hasError) {
|
||||
return (
|
||||
<div className="w-full px-4 py-3.5 border-b border-border last:border-b-0 bg-destructive/[0.03]">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-9 h-9 rounded-full bg-destructive/10 flex items-center justify-center shrink-0">
|
||||
<XIcon className="w-4 h-4 text-destructive" />
|
||||
</div>
|
||||
<span className="text-sm text-destructive/90">{t("inbox.failed-to-load")}</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={handleDeleteMessage}
|
||||
className="p-1.5 hover:bg-destructive/10 rounded-md transition-colors"
|
||||
title={t("common.delete")}
|
||||
>
|
||||
<TrashIcon className="w-3.5 h-3.5 text-destructive/70 hover:text-destructive" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
const isUnread = notification.status === UserNotification_Status.UNREAD;
|
||||
|
||||
return (
|
||||
<div className="w-full flex flex-row justify-start items-start gap-3">
|
||||
<div
|
||||
className={cn(
|
||||
"shrink-0 mt-2 p-2 rounded-full border",
|
||||
inbox.status === Inbox_Status.UNREAD
|
||||
? "border-primary text-primary bg-primary/10"
|
||||
: "border-muted-foreground text-muted-foreground bg-muted",
|
||||
)}
|
||||
>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<MessageCircleIcon className="w-4 sm:w-5 h-auto" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>Comment</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"border w-full p-2 px-3 rounded-lg flex flex-col justify-start items-start gap-1 border-border hover:bg-background",
|
||||
inbox.status !== Inbox_Status.UNREAD && "opacity-60",
|
||||
)}
|
||||
>
|
||||
{initialized ? (
|
||||
<>
|
||||
<div className="w-full flex flex-row justify-between items-center">
|
||||
<span className="text-sm text-muted-foreground">{inbox.createTime?.toLocaleString()}</span>
|
||||
{inbox.status === Inbox_Status.UNREAD ? archiveButton() : deleteButton()}
|
||||
<div
|
||||
className={cn(
|
||||
"w-full px-4 py-3.5 border-b border-border last:border-b-0 transition-colors group relative",
|
||||
isUnread ? "bg-primary/[0.02] hover:bg-primary/[0.04]" : "hover:bg-muted/40",
|
||||
)}
|
||||
>
|
||||
{/* Unread indicator bar */}
|
||||
{isUnread && <div className="absolute left-0 top-0 bottom-0 w-1 bg-primary" />}
|
||||
|
||||
<div className="flex items-start gap-3">
|
||||
{/* Avatar & Icon */}
|
||||
<div className="relative shrink-0 mt-0.5">
|
||||
<UserAvatar className="w-9 h-9" avatarUrl={sender?.avatarUrl} />
|
||||
<div
|
||||
className={cn(
|
||||
"absolute -bottom-0.5 -right-0.5 w-[18px] h-[18px] rounded-full border-[2px] border-background flex items-center justify-center shadow-sm",
|
||||
isUnread ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
<MessageCircleIcon className="w-2.5 h-2.5" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex-1 min-w-0">
|
||||
{/* Header */}
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<div className="flex-1 min-w-0 flex items-baseline gap-1.5 flex-wrap">
|
||||
<span className="font-semibold text-sm text-foreground">{sender?.displayName || sender?.username}</span>
|
||||
<span className="text-sm text-muted-foreground">commented on your memo</span>
|
||||
<span className="text-xs text-muted-foreground/80">
|
||||
· {notification.createTime?.toLocaleDateString([], { month: "short", day: "numeric" })} at{" "}
|
||||
{notification.createTime?.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}
|
||||
</span>
|
||||
</div>
|
||||
<p
|
||||
className="text-base leading-tight cursor-pointer text-muted-foreground hover:underline hover:text-primary"
|
||||
<div className="flex items-center gap-0.5 shrink-0">
|
||||
{isUnread ? (
|
||||
<button
|
||||
onClick={() => handleArchiveMessage()}
|
||||
className="p-1.5 hover:bg-background/80 rounded-md transition-all opacity-0 group-hover:opacity-100"
|
||||
title={t("common.archive")}
|
||||
>
|
||||
<CheckIcon className="w-3.5 h-3.5 text-muted-foreground hover:text-primary" />
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={handleDeleteMessage}
|
||||
className="p-1.5 hover:bg-background/80 rounded-md transition-all opacity-0 group-hover:opacity-100"
|
||||
title={t("common.delete")}
|
||||
>
|
||||
<TrashIcon className="w-3.5 h-3.5 text-muted-foreground hover:text-destructive" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Comment Preview */}
|
||||
{commentMemo && (
|
||||
<div
|
||||
onClick={handleNavigateToMemo}
|
||||
className="mt-2 p-3 rounded-md bg-muted/40 hover:bg-muted/60 cursor-pointer border border-border/50 hover:border-border transition-all group/comment"
|
||||
>
|
||||
{t("inbox.memo-comment", {
|
||||
user: sender?.displayName || sender?.username,
|
||||
memo: relatedMemo?.name,
|
||||
interpolation: { escapeValue: false },
|
||||
})}
|
||||
</p>
|
||||
</>
|
||||
) : hasError ? (
|
||||
<div className="w-full flex flex-row justify-between items-center">
|
||||
<span className="text-sm text-muted-foreground">{t("inbox.failed-to-load")}</span>
|
||||
{deleteButton()}
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-full flex flex-row justify-center items-center my-2">
|
||||
<LoaderIcon className="animate-spin text-muted-foreground" />
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-start gap-2">
|
||||
<MessageCircleIcon className="w-3.5 h-3.5 text-muted-foreground/60 shrink-0 mt-0.5" />
|
||||
<p className="text-[13px] text-foreground/90 line-clamp-2 leading-relaxed group-hover/comment:text-foreground transition-colors">
|
||||
{commentMemo.content || <span className="italic text-muted-foreground">Empty comment</span>}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { EarthIcon, LibraryIcon, PaperclipIcon, UserCircleIcon } from "lucide-react";
|
||||
import { BellIcon, EarthIcon, LibraryIcon, PaperclipIcon, UserCircleIcon } from "lucide-react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { useEffect } from "react";
|
||||
import { NavLink } from "react-router-dom";
|
||||
|
|
@ -33,7 +33,7 @@ const Navigation = observer((props: Props) => {
|
|||
return;
|
||||
}
|
||||
|
||||
userStore.fetchInboxes();
|
||||
userStore.fetchNotifications();
|
||||
}, []);
|
||||
|
||||
const homeNavLink: NavLinkItem = {
|
||||
|
|
@ -54,6 +54,22 @@ const Navigation = observer((props: Props) => {
|
|||
title: t("common.attachments"),
|
||||
icon: <PaperclipIcon className="w-6 h-auto shrink-0" />,
|
||||
};
|
||||
const unreadCount = userStore.state.notifications.filter((n) => n.status === "UNREAD").length;
|
||||
const inboxNavLink: NavLinkItem = {
|
||||
id: "header-inbox",
|
||||
path: Routes.INBOX,
|
||||
title: t("common.inbox"),
|
||||
icon: (
|
||||
<div className="relative">
|
||||
<BellIcon className="w-6 h-auto shrink-0" />
|
||||
{unreadCount > 0 && (
|
||||
<span className="absolute -top-1 -right-1 min-w-[18px] h-[18px] px-1 flex items-center justify-center bg-primary text-primary-foreground text-[10px] font-semibold rounded-full border-2 border-background">
|
||||
{unreadCount > 99 ? "99+" : unreadCount}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
};
|
||||
const signInNavLink: NavLinkItem = {
|
||||
id: "header-auth",
|
||||
path: Routes.AUTH,
|
||||
|
|
@ -61,7 +77,9 @@ const Navigation = observer((props: Props) => {
|
|||
icon: <UserCircleIcon className="w-6 h-auto shrink-0" />,
|
||||
};
|
||||
|
||||
const navLinks: NavLinkItem[] = currentUser ? [homeNavLink, exploreNavLink, attachmentsNavLink] : [exploreNavLink, signInNavLink];
|
||||
const navLinks: NavLinkItem[] = currentUser
|
||||
? [homeNavLink, exploreNavLink, attachmentsNavLink, inboxNavLink]
|
||||
: [exploreNavLink, signInNavLink];
|
||||
|
||||
return (
|
||||
<header className={cn("w-full h-full overflow-auto flex flex-col justify-between items-start gap-4 hide-scrollbar", className)}>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,4 @@
|
|||
import {
|
||||
ArchiveIcon,
|
||||
LogOutIcon,
|
||||
User2Icon,
|
||||
SquareUserIcon,
|
||||
SettingsIcon,
|
||||
BellIcon,
|
||||
GlobeIcon,
|
||||
PaletteIcon,
|
||||
CheckIcon,
|
||||
} from "lucide-react";
|
||||
import { ArchiveIcon, LogOutIcon, User2Icon, SquareUserIcon, SettingsIcon, GlobeIcon, PaletteIcon, CheckIcon } from "lucide-react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { authServiceClient } from "@/grpcweb";
|
||||
import useCurrentUser from "@/hooks/useCurrentUser";
|
||||
|
|
@ -99,10 +89,6 @@ const UserMenu = observer((props: Props) => {
|
|||
<ArchiveIcon className="size-4 text-muted-foreground" />
|
||||
{t("common.archived")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => navigateTo(Routes.INBOX)}>
|
||||
<BellIcon className="size-4 text-muted-foreground" />
|
||||
{t("common.inbox")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<GlobeIcon className="size-4 text-muted-foreground" />
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import { ActivityServiceDefinition } from "./types/proto/api/v1/activity_service
|
|||
import { AttachmentServiceDefinition } from "./types/proto/api/v1/attachment_service";
|
||||
import { AuthServiceDefinition } from "./types/proto/api/v1/auth_service";
|
||||
import { IdentityProviderServiceDefinition } from "./types/proto/api/v1/idp_service";
|
||||
import { InboxServiceDefinition } from "./types/proto/api/v1/inbox_service";
|
||||
import { MemoServiceDefinition } from "./types/proto/api/v1/memo_service";
|
||||
import { ShortcutServiceDefinition } from "./types/proto/api/v1/shortcut_service";
|
||||
import { UserServiceDefinition } from "./types/proto/api/v1/user_service";
|
||||
|
|
@ -30,8 +29,6 @@ export const attachmentServiceClient = clientFactory.create(AttachmentServiceDef
|
|||
|
||||
export const shortcutServiceClient = clientFactory.create(ShortcutServiceDefinition, channel);
|
||||
|
||||
export const inboxServiceClient = clientFactory.create(InboxServiceDefinition, channel);
|
||||
|
||||
export const activityServiceClient = clientFactory.create(ActivityServiceDefinition, channel);
|
||||
|
||||
export const identityProviderServiceClient = clientFactory.create(IdentityProviderServiceDefinition, channel);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
"about": "About",
|
||||
"add": "Add",
|
||||
"admin": "Admin",
|
||||
"all": "All",
|
||||
"archive": "Archive",
|
||||
"archived": "Archived",
|
||||
"attachments": "Attachments",
|
||||
|
|
@ -125,8 +126,10 @@
|
|||
},
|
||||
"inbox": {
|
||||
"memo-comment": "{{user}} has a comment on your {{memo}}.",
|
||||
"version-update": "New version {{version}} is available now!",
|
||||
"failed-to-load": "Failed to load inbox item"
|
||||
"failed-to-load": "Failed to load inbox item",
|
||||
"unread": "Unread",
|
||||
"no-unread": "No unread notifications",
|
||||
"no-archived": "No archived notifications"
|
||||
},
|
||||
"markdown": {
|
||||
"checkbox": "Checkbox",
|
||||
|
|
|
|||
|
|
@ -1,63 +1,126 @@
|
|||
import { sortBy } from "lodash-es";
|
||||
import { BellIcon } from "lucide-react";
|
||||
import { ArchiveIcon, BellIcon, InboxIcon } from "lucide-react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import Empty from "@/components/Empty";
|
||||
import MemoCommentMessage from "@/components/Inbox/MemoCommentMessage";
|
||||
import MobileHeader from "@/components/MobileHeader";
|
||||
import useResponsiveWidth from "@/hooks/useResponsiveWidth";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { userStore } from "@/store";
|
||||
import { Inbox, Inbox_Status, Inbox_Type } from "@/types/proto/api/v1/inbox_service";
|
||||
import { UserNotification, UserNotification_Status, UserNotification_Type } from "@/types/proto/api/v1/user_service";
|
||||
import { useTranslate } from "@/utils/i18n";
|
||||
|
||||
const Inboxes = observer(() => {
|
||||
const t = useTranslate();
|
||||
const { md } = useResponsiveWidth();
|
||||
const [filter, setFilter] = useState<"all" | "unread" | "archived">("all");
|
||||
|
||||
const inboxes = sortBy(userStore.state.inboxes, (inbox: Inbox) => {
|
||||
if (inbox.status === Inbox_Status.UNREAD) return 0;
|
||||
if (inbox.status === Inbox_Status.ARCHIVED) return 1;
|
||||
return 2;
|
||||
const allNotifications = sortBy(userStore.state.notifications, (notification: UserNotification) => {
|
||||
return -(notification.createTime?.getTime() || 0);
|
||||
});
|
||||
|
||||
const fetchInboxes = async () => {
|
||||
const notifications = allNotifications.filter((notification) => {
|
||||
if (filter === "unread") return notification.status === UserNotification_Status.UNREAD;
|
||||
if (filter === "archived") return notification.status === UserNotification_Status.ARCHIVED;
|
||||
return true;
|
||||
});
|
||||
|
||||
const unreadCount = allNotifications.filter((n) => n.status === UserNotification_Status.UNREAD).length;
|
||||
const archivedCount = allNotifications.filter((n) => n.status === UserNotification_Status.ARCHIVED).length;
|
||||
|
||||
const fetchNotifications = async () => {
|
||||
try {
|
||||
await userStore.fetchInboxes();
|
||||
await userStore.fetchNotifications();
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch inboxes:", error);
|
||||
console.error("Failed to fetch notifications:", error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchInboxes();
|
||||
fetchNotifications();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<section className="@container w-full max-w-5xl min-h-full flex flex-col justify-start items-center sm:pt-3 md:pt-6 pb-8">
|
||||
{!md && <MobileHeader />}
|
||||
<div className="w-full px-4 sm:px-6">
|
||||
<div className="w-full border border-border flex flex-col justify-start items-start px-4 py-3 rounded-xl bg-background text-foreground">
|
||||
<div className="relative w-full flex flex-row justify-between items-center">
|
||||
<p className="py-1 flex flex-row justify-start items-center select-none opacity-80">
|
||||
<BellIcon className="w-6 h-auto mr-1 opacity-80" />
|
||||
<span className="text-lg">{t("common.inbox")}</span>
|
||||
</p>
|
||||
<div className="w-full border border-border flex flex-col justify-start items-start rounded-xl bg-background text-foreground overflow-hidden">
|
||||
{/* Header */}
|
||||
<div className="w-full px-4 py-4 border-b border-border">
|
||||
<div className="flex flex-row justify-between items-center">
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<BellIcon className="w-5 h-auto text-muted-foreground" />
|
||||
<h1 className="text-xl font-semibold">{t("common.inbox")}</h1>
|
||||
{unreadCount > 0 && (
|
||||
<span className="ml-1 px-2 py-0.5 text-xs font-medium rounded-full bg-primary text-primary-foreground">
|
||||
{unreadCount}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full h-auto flex flex-col justify-start items-start px-2 pb-4">
|
||||
{inboxes.length === 0 && (
|
||||
<div className="w-full mt-4 mb-8 flex flex-col justify-center items-center italic">
|
||||
|
||||
{/* Filter Tabs */}
|
||||
<div className="w-full px-4 py-2 border-b border-border bg-muted/30">
|
||||
<div className="flex flex-row gap-1">
|
||||
<button
|
||||
onClick={() => setFilter("all")}
|
||||
className={cn(
|
||||
"px-3 py-1.5 text-sm font-medium rounded-md transition-colors",
|
||||
filter === "all"
|
||||
? "bg-background text-foreground shadow-sm"
|
||||
: "text-muted-foreground hover:text-foreground hover:bg-background/50",
|
||||
)}
|
||||
>
|
||||
{t("common.all")} ({allNotifications.length})
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setFilter("unread")}
|
||||
className={cn(
|
||||
"px-3 py-1.5 text-sm font-medium rounded-md transition-colors flex items-center gap-1.5",
|
||||
filter === "unread"
|
||||
? "bg-background text-foreground shadow-sm"
|
||||
: "text-muted-foreground hover:text-foreground hover:bg-background/50",
|
||||
)}
|
||||
>
|
||||
<InboxIcon className="w-3.5 h-auto" />
|
||||
{t("inbox.unread")} ({unreadCount})
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setFilter("archived")}
|
||||
className={cn(
|
||||
"px-3 py-1.5 text-sm font-medium rounded-md transition-colors flex items-center gap-1.5",
|
||||
filter === "archived"
|
||||
? "bg-background text-foreground shadow-sm"
|
||||
: "text-muted-foreground hover:text-foreground hover:bg-background/50",
|
||||
)}
|
||||
>
|
||||
<ArchiveIcon className="w-3.5 h-auto" />
|
||||
{t("common.archived")} ({archivedCount})
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Notifications List */}
|
||||
<div className="w-full">
|
||||
{notifications.length === 0 ? (
|
||||
<div className="w-full py-16 flex flex-col justify-center items-center">
|
||||
<Empty />
|
||||
<p className="mt-4 text-muted-foreground">{t("message.no-data")}</p>
|
||||
<p className="mt-4 text-sm text-muted-foreground">
|
||||
{filter === "unread" ? t("inbox.no-unread") : filter === "archived" ? t("inbox.no-archived") : t("message.no-data")}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col">
|
||||
{notifications.map((notification: UserNotification) => {
|
||||
if (notification.type === UserNotification_Type.MEMO_COMMENT) {
|
||||
return <MemoCommentMessage key={notification.name} notification={notification} />;
|
||||
}
|
||||
return null;
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col justify-start items-start w-full mt-4 gap-4">
|
||||
{inboxes.map((inbox: Inbox) => {
|
||||
if (inbox.type === Inbox_Type.MEMO_COMMENT) {
|
||||
return <MemoCommentMessage key={`${inbox.name}-${inbox.status}`} inbox={inbox} />;
|
||||
}
|
||||
return undefined;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { uniqueId } from "lodash-es";
|
||||
import { makeAutoObservable, computed } from "mobx";
|
||||
import { authServiceClient, inboxServiceClient, userServiceClient, shortcutServiceClient } from "@/grpcweb";
|
||||
import { Inbox } from "@/types/proto/api/v1/inbox_service";
|
||||
import { authServiceClient, userServiceClient, shortcutServiceClient } from "@/grpcweb";
|
||||
import { Shortcut } from "@/types/proto/api/v1/shortcut_service";
|
||||
import {
|
||||
User,
|
||||
UserNotification,
|
||||
UserSetting,
|
||||
UserSetting_Key,
|
||||
UserSetting_GeneralSetting,
|
||||
|
|
@ -24,7 +24,7 @@ class LocalState {
|
|||
userAccessTokensSetting?: UserSetting_AccessTokensSetting;
|
||||
userWebhooksSetting?: UserSetting_WebhooksSetting;
|
||||
shortcuts: Shortcut[] = [];
|
||||
inboxes: Inbox[] = [];
|
||||
notifications: UserNotification[] = [];
|
||||
userMapByName: Record<string, User> = {};
|
||||
userStatsByName: Record<string, UserStats> = {};
|
||||
|
||||
|
|
@ -218,40 +218,40 @@ const userStore = (() => {
|
|||
// Note: fetchShortcuts is now handled by fetchUserSettings
|
||||
// The shortcuts are extracted from the user shortcuts setting
|
||||
|
||||
const fetchInboxes = async () => {
|
||||
const fetchNotifications = async () => {
|
||||
if (!state.currentUser) {
|
||||
throw new Error("No current user available");
|
||||
}
|
||||
|
||||
const { inboxes } = await inboxServiceClient.listInboxes({
|
||||
const { notifications } = await userServiceClient.listUserNotifications({
|
||||
parent: state.currentUser,
|
||||
});
|
||||
|
||||
state.setPartial({
|
||||
inboxes,
|
||||
notifications,
|
||||
});
|
||||
};
|
||||
|
||||
const updateInbox = async (inbox: Partial<Inbox>, updateMask: string[]) => {
|
||||
const updatedInbox = await inboxServiceClient.updateInbox({
|
||||
inbox,
|
||||
const updateNotification = async (notification: Partial<UserNotification>, updateMask: string[]) => {
|
||||
const updatedNotification = await userServiceClient.updateUserNotification({
|
||||
notification,
|
||||
updateMask,
|
||||
});
|
||||
state.setPartial({
|
||||
inboxes: state.inboxes.map((i) => {
|
||||
if (i.name === updatedInbox.name) {
|
||||
return updatedInbox;
|
||||
notifications: state.notifications.map((n) => {
|
||||
if (n.name === updatedNotification.name) {
|
||||
return updatedNotification;
|
||||
}
|
||||
return i;
|
||||
return n;
|
||||
}),
|
||||
});
|
||||
return updatedInbox;
|
||||
return updatedNotification;
|
||||
};
|
||||
|
||||
const deleteInbox = async (name: string) => {
|
||||
await inboxServiceClient.deleteInbox({ name });
|
||||
const deleteNotification = async (name: string) => {
|
||||
await userServiceClient.deleteUserNotification({ name });
|
||||
state.setPartial({
|
||||
inboxes: state.inboxes.filter((i) => i.name !== name),
|
||||
notifications: state.notifications.filter((n) => n.name !== name),
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -296,9 +296,9 @@ const userStore = (() => {
|
|||
updateUserGeneralSetting,
|
||||
getUserGeneralSetting,
|
||||
fetchUserSettings,
|
||||
fetchInboxes,
|
||||
updateInbox,
|
||||
deleteInbox,
|
||||
fetchNotifications,
|
||||
updateNotification,
|
||||
deleteNotification,
|
||||
fetchUserStats,
|
||||
setStatsStateId,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -39,8 +39,6 @@ export enum Activity_Type {
|
|||
TYPE_UNSPECIFIED = "TYPE_UNSPECIFIED",
|
||||
/** MEMO_COMMENT - Memo comment activity. */
|
||||
MEMO_COMMENT = "MEMO_COMMENT",
|
||||
/** VERSION_UPDATE - Version update activity. */
|
||||
VERSION_UPDATE = "VERSION_UPDATE",
|
||||
UNRECOGNIZED = "UNRECOGNIZED",
|
||||
}
|
||||
|
||||
|
|
@ -52,9 +50,6 @@ export function activity_TypeFromJSON(object: any): Activity_Type {
|
|||
case 1:
|
||||
case "MEMO_COMMENT":
|
||||
return Activity_Type.MEMO_COMMENT;
|
||||
case 2:
|
||||
case "VERSION_UPDATE":
|
||||
return Activity_Type.VERSION_UPDATE;
|
||||
case -1:
|
||||
case "UNRECOGNIZED":
|
||||
default:
|
||||
|
|
@ -68,8 +63,6 @@ export function activity_TypeToNumber(object: Activity_Type): number {
|
|||
return 0;
|
||||
case Activity_Type.MEMO_COMMENT:
|
||||
return 1;
|
||||
case Activity_Type.VERSION_UPDATE:
|
||||
return 2;
|
||||
case Activity_Type.UNRECOGNIZED:
|
||||
default:
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -89,8 +89,6 @@ export enum Inbox_Type {
|
|||
TYPE_UNSPECIFIED = "TYPE_UNSPECIFIED",
|
||||
/** MEMO_COMMENT - Memo comment notification. */
|
||||
MEMO_COMMENT = "MEMO_COMMENT",
|
||||
/** VERSION_UPDATE - Version update notification. */
|
||||
VERSION_UPDATE = "VERSION_UPDATE",
|
||||
UNRECOGNIZED = "UNRECOGNIZED",
|
||||
}
|
||||
|
||||
|
|
@ -102,9 +100,6 @@ export function inbox_TypeFromJSON(object: any): Inbox_Type {
|
|||
case 1:
|
||||
case "MEMO_COMMENT":
|
||||
return Inbox_Type.MEMO_COMMENT;
|
||||
case 2:
|
||||
case "VERSION_UPDATE":
|
||||
return Inbox_Type.VERSION_UPDATE;
|
||||
case -1:
|
||||
case "UNRECOGNIZED":
|
||||
default:
|
||||
|
|
@ -118,8 +113,6 @@ export function inbox_TypeToNumber(object: Inbox_Type): number {
|
|||
return 0;
|
||||
case Inbox_Type.MEMO_COMMENT:
|
||||
return 1;
|
||||
case Inbox_Type.VERSION_UPDATE:
|
||||
return 2;
|
||||
case Inbox_Type.UNRECOGNIZED:
|
||||
default:
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -579,6 +579,127 @@ export interface DeleteUserWebhookRequest {
|
|||
name: string;
|
||||
}
|
||||
|
||||
export interface UserNotification {
|
||||
/**
|
||||
* The resource name of the notification.
|
||||
* Format: users/{user}/notifications/{notification}
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* The sender of the notification.
|
||||
* Format: users/{user}
|
||||
*/
|
||||
sender: string;
|
||||
/** The status of the notification. */
|
||||
status: UserNotification_Status;
|
||||
/** The creation timestamp. */
|
||||
createTime?:
|
||||
| Date
|
||||
| undefined;
|
||||
/** The type of the notification. */
|
||||
type: UserNotification_Type;
|
||||
/** The activity ID associated with this notification. */
|
||||
activityId?: number | undefined;
|
||||
}
|
||||
|
||||
export enum UserNotification_Status {
|
||||
STATUS_UNSPECIFIED = "STATUS_UNSPECIFIED",
|
||||
UNREAD = "UNREAD",
|
||||
ARCHIVED = "ARCHIVED",
|
||||
UNRECOGNIZED = "UNRECOGNIZED",
|
||||
}
|
||||
|
||||
export function userNotification_StatusFromJSON(object: any): UserNotification_Status {
|
||||
switch (object) {
|
||||
case 0:
|
||||
case "STATUS_UNSPECIFIED":
|
||||
return UserNotification_Status.STATUS_UNSPECIFIED;
|
||||
case 1:
|
||||
case "UNREAD":
|
||||
return UserNotification_Status.UNREAD;
|
||||
case 2:
|
||||
case "ARCHIVED":
|
||||
return UserNotification_Status.ARCHIVED;
|
||||
case -1:
|
||||
case "UNRECOGNIZED":
|
||||
default:
|
||||
return UserNotification_Status.UNRECOGNIZED;
|
||||
}
|
||||
}
|
||||
|
||||
export function userNotification_StatusToNumber(object: UserNotification_Status): number {
|
||||
switch (object) {
|
||||
case UserNotification_Status.STATUS_UNSPECIFIED:
|
||||
return 0;
|
||||
case UserNotification_Status.UNREAD:
|
||||
return 1;
|
||||
case UserNotification_Status.ARCHIVED:
|
||||
return 2;
|
||||
case UserNotification_Status.UNRECOGNIZED:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
export enum UserNotification_Type {
|
||||
TYPE_UNSPECIFIED = "TYPE_UNSPECIFIED",
|
||||
MEMO_COMMENT = "MEMO_COMMENT",
|
||||
UNRECOGNIZED = "UNRECOGNIZED",
|
||||
}
|
||||
|
||||
export function userNotification_TypeFromJSON(object: any): UserNotification_Type {
|
||||
switch (object) {
|
||||
case 0:
|
||||
case "TYPE_UNSPECIFIED":
|
||||
return UserNotification_Type.TYPE_UNSPECIFIED;
|
||||
case 1:
|
||||
case "MEMO_COMMENT":
|
||||
return UserNotification_Type.MEMO_COMMENT;
|
||||
case -1:
|
||||
case "UNRECOGNIZED":
|
||||
default:
|
||||
return UserNotification_Type.UNRECOGNIZED;
|
||||
}
|
||||
}
|
||||
|
||||
export function userNotification_TypeToNumber(object: UserNotification_Type): number {
|
||||
switch (object) {
|
||||
case UserNotification_Type.TYPE_UNSPECIFIED:
|
||||
return 0;
|
||||
case UserNotification_Type.MEMO_COMMENT:
|
||||
return 1;
|
||||
case UserNotification_Type.UNRECOGNIZED:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ListUserNotificationsRequest {
|
||||
/**
|
||||
* The parent user resource.
|
||||
* Format: users/{user}
|
||||
*/
|
||||
parent: string;
|
||||
pageSize: number;
|
||||
pageToken: string;
|
||||
filter: string;
|
||||
}
|
||||
|
||||
export interface ListUserNotificationsResponse {
|
||||
notifications: UserNotification[];
|
||||
nextPageToken: string;
|
||||
}
|
||||
|
||||
export interface UpdateUserNotificationRequest {
|
||||
notification?: UserNotification | undefined;
|
||||
updateMask?: string[] | undefined;
|
||||
}
|
||||
|
||||
export interface DeleteUserNotificationRequest {
|
||||
/** Format: users/{user}/notifications/{notification} */
|
||||
name: string;
|
||||
}
|
||||
|
||||
function createBaseUser(): User {
|
||||
return {
|
||||
name: "",
|
||||
|
|
@ -3206,6 +3327,365 @@ export const DeleteUserWebhookRequest: MessageFns<DeleteUserWebhookRequest> = {
|
|||
},
|
||||
};
|
||||
|
||||
function createBaseUserNotification(): UserNotification {
|
||||
return {
|
||||
name: "",
|
||||
sender: "",
|
||||
status: UserNotification_Status.STATUS_UNSPECIFIED,
|
||||
createTime: undefined,
|
||||
type: UserNotification_Type.TYPE_UNSPECIFIED,
|
||||
activityId: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
export const UserNotification: MessageFns<UserNotification> = {
|
||||
encode(message: UserNotification, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.name !== "") {
|
||||
writer.uint32(10).string(message.name);
|
||||
}
|
||||
if (message.sender !== "") {
|
||||
writer.uint32(18).string(message.sender);
|
||||
}
|
||||
if (message.status !== UserNotification_Status.STATUS_UNSPECIFIED) {
|
||||
writer.uint32(24).int32(userNotification_StatusToNumber(message.status));
|
||||
}
|
||||
if (message.createTime !== undefined) {
|
||||
Timestamp.encode(toTimestamp(message.createTime), writer.uint32(34).fork()).join();
|
||||
}
|
||||
if (message.type !== UserNotification_Type.TYPE_UNSPECIFIED) {
|
||||
writer.uint32(40).int32(userNotification_TypeToNumber(message.type));
|
||||
}
|
||||
if (message.activityId !== undefined) {
|
||||
writer.uint32(48).int32(message.activityId);
|
||||
}
|
||||
return writer;
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): UserNotification {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
let end = length === undefined ? reader.len : reader.pos + length;
|
||||
const message = createBaseUserNotification();
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32();
|
||||
switch (tag >>> 3) {
|
||||
case 1: {
|
||||
if (tag !== 10) {
|
||||
break;
|
||||
}
|
||||
|
||||
message.name = reader.string();
|
||||
continue;
|
||||
}
|
||||
case 2: {
|
||||
if (tag !== 18) {
|
||||
break;
|
||||
}
|
||||
|
||||
message.sender = reader.string();
|
||||
continue;
|
||||
}
|
||||
case 3: {
|
||||
if (tag !== 24) {
|
||||
break;
|
||||
}
|
||||
|
||||
message.status = userNotification_StatusFromJSON(reader.int32());
|
||||
continue;
|
||||
}
|
||||
case 4: {
|
||||
if (tag !== 34) {
|
||||
break;
|
||||
}
|
||||
|
||||
message.createTime = fromTimestamp(Timestamp.decode(reader, reader.uint32()));
|
||||
continue;
|
||||
}
|
||||
case 5: {
|
||||
if (tag !== 40) {
|
||||
break;
|
||||
}
|
||||
|
||||
message.type = userNotification_TypeFromJSON(reader.int32());
|
||||
continue;
|
||||
}
|
||||
case 6: {
|
||||
if (tag !== 48) {
|
||||
break;
|
||||
}
|
||||
|
||||
message.activityId = reader.int32();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break;
|
||||
}
|
||||
reader.skip(tag & 7);
|
||||
}
|
||||
return message;
|
||||
},
|
||||
|
||||
create(base?: DeepPartial<UserNotification>): UserNotification {
|
||||
return UserNotification.fromPartial(base ?? {});
|
||||
},
|
||||
fromPartial(object: DeepPartial<UserNotification>): UserNotification {
|
||||
const message = createBaseUserNotification();
|
||||
message.name = object.name ?? "";
|
||||
message.sender = object.sender ?? "";
|
||||
message.status = object.status ?? UserNotification_Status.STATUS_UNSPECIFIED;
|
||||
message.createTime = object.createTime ?? undefined;
|
||||
message.type = object.type ?? UserNotification_Type.TYPE_UNSPECIFIED;
|
||||
message.activityId = object.activityId ?? undefined;
|
||||
return message;
|
||||
},
|
||||
};
|
||||
|
||||
function createBaseListUserNotificationsRequest(): ListUserNotificationsRequest {
|
||||
return { parent: "", pageSize: 0, pageToken: "", filter: "" };
|
||||
}
|
||||
|
||||
export const ListUserNotificationsRequest: MessageFns<ListUserNotificationsRequest> = {
|
||||
encode(message: ListUserNotificationsRequest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.parent !== "") {
|
||||
writer.uint32(10).string(message.parent);
|
||||
}
|
||||
if (message.pageSize !== 0) {
|
||||
writer.uint32(16).int32(message.pageSize);
|
||||
}
|
||||
if (message.pageToken !== "") {
|
||||
writer.uint32(26).string(message.pageToken);
|
||||
}
|
||||
if (message.filter !== "") {
|
||||
writer.uint32(34).string(message.filter);
|
||||
}
|
||||
return writer;
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): ListUserNotificationsRequest {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
let end = length === undefined ? reader.len : reader.pos + length;
|
||||
const message = createBaseListUserNotificationsRequest();
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32();
|
||||
switch (tag >>> 3) {
|
||||
case 1: {
|
||||
if (tag !== 10) {
|
||||
break;
|
||||
}
|
||||
|
||||
message.parent = reader.string();
|
||||
continue;
|
||||
}
|
||||
case 2: {
|
||||
if (tag !== 16) {
|
||||
break;
|
||||
}
|
||||
|
||||
message.pageSize = reader.int32();
|
||||
continue;
|
||||
}
|
||||
case 3: {
|
||||
if (tag !== 26) {
|
||||
break;
|
||||
}
|
||||
|
||||
message.pageToken = reader.string();
|
||||
continue;
|
||||
}
|
||||
case 4: {
|
||||
if (tag !== 34) {
|
||||
break;
|
||||
}
|
||||
|
||||
message.filter = reader.string();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break;
|
||||
}
|
||||
reader.skip(tag & 7);
|
||||
}
|
||||
return message;
|
||||
},
|
||||
|
||||
create(base?: DeepPartial<ListUserNotificationsRequest>): ListUserNotificationsRequest {
|
||||
return ListUserNotificationsRequest.fromPartial(base ?? {});
|
||||
},
|
||||
fromPartial(object: DeepPartial<ListUserNotificationsRequest>): ListUserNotificationsRequest {
|
||||
const message = createBaseListUserNotificationsRequest();
|
||||
message.parent = object.parent ?? "";
|
||||
message.pageSize = object.pageSize ?? 0;
|
||||
message.pageToken = object.pageToken ?? "";
|
||||
message.filter = object.filter ?? "";
|
||||
return message;
|
||||
},
|
||||
};
|
||||
|
||||
function createBaseListUserNotificationsResponse(): ListUserNotificationsResponse {
|
||||
return { notifications: [], nextPageToken: "" };
|
||||
}
|
||||
|
||||
export const ListUserNotificationsResponse: MessageFns<ListUserNotificationsResponse> = {
|
||||
encode(message: ListUserNotificationsResponse, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
for (const v of message.notifications) {
|
||||
UserNotification.encode(v!, writer.uint32(10).fork()).join();
|
||||
}
|
||||
if (message.nextPageToken !== "") {
|
||||
writer.uint32(18).string(message.nextPageToken);
|
||||
}
|
||||
return writer;
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): ListUserNotificationsResponse {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
let end = length === undefined ? reader.len : reader.pos + length;
|
||||
const message = createBaseListUserNotificationsResponse();
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32();
|
||||
switch (tag >>> 3) {
|
||||
case 1: {
|
||||
if (tag !== 10) {
|
||||
break;
|
||||
}
|
||||
|
||||
message.notifications.push(UserNotification.decode(reader, reader.uint32()));
|
||||
continue;
|
||||
}
|
||||
case 2: {
|
||||
if (tag !== 18) {
|
||||
break;
|
||||
}
|
||||
|
||||
message.nextPageToken = reader.string();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break;
|
||||
}
|
||||
reader.skip(tag & 7);
|
||||
}
|
||||
return message;
|
||||
},
|
||||
|
||||
create(base?: DeepPartial<ListUserNotificationsResponse>): ListUserNotificationsResponse {
|
||||
return ListUserNotificationsResponse.fromPartial(base ?? {});
|
||||
},
|
||||
fromPartial(object: DeepPartial<ListUserNotificationsResponse>): ListUserNotificationsResponse {
|
||||
const message = createBaseListUserNotificationsResponse();
|
||||
message.notifications = object.notifications?.map((e) => UserNotification.fromPartial(e)) || [];
|
||||
message.nextPageToken = object.nextPageToken ?? "";
|
||||
return message;
|
||||
},
|
||||
};
|
||||
|
||||
function createBaseUpdateUserNotificationRequest(): UpdateUserNotificationRequest {
|
||||
return { notification: undefined, updateMask: undefined };
|
||||
}
|
||||
|
||||
export const UpdateUserNotificationRequest: MessageFns<UpdateUserNotificationRequest> = {
|
||||
encode(message: UpdateUserNotificationRequest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.notification !== undefined) {
|
||||
UserNotification.encode(message.notification, writer.uint32(10).fork()).join();
|
||||
}
|
||||
if (message.updateMask !== undefined) {
|
||||
FieldMask.encode(FieldMask.wrap(message.updateMask), writer.uint32(18).fork()).join();
|
||||
}
|
||||
return writer;
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): UpdateUserNotificationRequest {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
let end = length === undefined ? reader.len : reader.pos + length;
|
||||
const message = createBaseUpdateUserNotificationRequest();
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32();
|
||||
switch (tag >>> 3) {
|
||||
case 1: {
|
||||
if (tag !== 10) {
|
||||
break;
|
||||
}
|
||||
|
||||
message.notification = UserNotification.decode(reader, reader.uint32());
|
||||
continue;
|
||||
}
|
||||
case 2: {
|
||||
if (tag !== 18) {
|
||||
break;
|
||||
}
|
||||
|
||||
message.updateMask = FieldMask.unwrap(FieldMask.decode(reader, reader.uint32()));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break;
|
||||
}
|
||||
reader.skip(tag & 7);
|
||||
}
|
||||
return message;
|
||||
},
|
||||
|
||||
create(base?: DeepPartial<UpdateUserNotificationRequest>): UpdateUserNotificationRequest {
|
||||
return UpdateUserNotificationRequest.fromPartial(base ?? {});
|
||||
},
|
||||
fromPartial(object: DeepPartial<UpdateUserNotificationRequest>): UpdateUserNotificationRequest {
|
||||
const message = createBaseUpdateUserNotificationRequest();
|
||||
message.notification = (object.notification !== undefined && object.notification !== null)
|
||||
? UserNotification.fromPartial(object.notification)
|
||||
: undefined;
|
||||
message.updateMask = object.updateMask ?? undefined;
|
||||
return message;
|
||||
},
|
||||
};
|
||||
|
||||
function createBaseDeleteUserNotificationRequest(): DeleteUserNotificationRequest {
|
||||
return { name: "" };
|
||||
}
|
||||
|
||||
export const DeleteUserNotificationRequest: MessageFns<DeleteUserNotificationRequest> = {
|
||||
encode(message: DeleteUserNotificationRequest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.name !== "") {
|
||||
writer.uint32(10).string(message.name);
|
||||
}
|
||||
return writer;
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): DeleteUserNotificationRequest {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
let end = length === undefined ? reader.len : reader.pos + length;
|
||||
const message = createBaseDeleteUserNotificationRequest();
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32();
|
||||
switch (tag >>> 3) {
|
||||
case 1: {
|
||||
if (tag !== 10) {
|
||||
break;
|
||||
}
|
||||
|
||||
message.name = reader.string();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((tag & 7) === 4 || tag === 0) {
|
||||
break;
|
||||
}
|
||||
reader.skip(tag & 7);
|
||||
}
|
||||
return message;
|
||||
},
|
||||
|
||||
create(base?: DeepPartial<DeleteUserNotificationRequest>): DeleteUserNotificationRequest {
|
||||
return DeleteUserNotificationRequest.fromPartial(base ?? {});
|
||||
},
|
||||
fromPartial(object: DeepPartial<DeleteUserNotificationRequest>): DeleteUserNotificationRequest {
|
||||
const message = createBaseDeleteUserNotificationRequest();
|
||||
message.name = object.name ?? "";
|
||||
return message;
|
||||
},
|
||||
};
|
||||
|
||||
export type UserServiceDefinition = typeof UserServiceDefinition;
|
||||
export const UserServiceDefinition = {
|
||||
name: "UserService",
|
||||
|
|
@ -4317,6 +4797,235 @@ export const UserServiceDefinition = {
|
|||
},
|
||||
},
|
||||
},
|
||||
/** ListUserNotifications lists notifications for a user. */
|
||||
listUserNotifications: {
|
||||
name: "ListUserNotifications",
|
||||
requestType: ListUserNotificationsRequest,
|
||||
requestStream: false,
|
||||
responseType: ListUserNotificationsResponse,
|
||||
responseStream: false,
|
||||
options: {
|
||||
_unknownFields: {
|
||||
8410: [new Uint8Array([6, 112, 97, 114, 101, 110, 116])],
|
||||
578365826: [
|
||||
new Uint8Array([
|
||||
40,
|
||||
18,
|
||||
38,
|
||||
47,
|
||||
97,
|
||||
112,
|
||||
105,
|
||||
47,
|
||||
118,
|
||||
49,
|
||||
47,
|
||||
123,
|
||||
112,
|
||||
97,
|
||||
114,
|
||||
101,
|
||||
110,
|
||||
116,
|
||||
61,
|
||||
117,
|
||||
115,
|
||||
101,
|
||||
114,
|
||||
115,
|
||||
47,
|
||||
42,
|
||||
125,
|
||||
47,
|
||||
110,
|
||||
111,
|
||||
116,
|
||||
105,
|
||||
102,
|
||||
105,
|
||||
99,
|
||||
97,
|
||||
116,
|
||||
105,
|
||||
111,
|
||||
110,
|
||||
115,
|
||||
]),
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
/** UpdateUserNotification updates a notification. */
|
||||
updateUserNotification: {
|
||||
name: "UpdateUserNotification",
|
||||
requestType: UpdateUserNotificationRequest,
|
||||
requestStream: false,
|
||||
responseType: UserNotification,
|
||||
responseStream: false,
|
||||
options: {
|
||||
_unknownFields: {
|
||||
8410: [
|
||||
new Uint8Array([
|
||||
24,
|
||||
110,
|
||||
111,
|
||||
116,
|
||||
105,
|
||||
102,
|
||||
105,
|
||||
99,
|
||||
97,
|
||||
116,
|
||||
105,
|
||||
111,
|
||||
110,
|
||||
44,
|
||||
117,
|
||||
112,
|
||||
100,
|
||||
97,
|
||||
116,
|
||||
101,
|
||||
95,
|
||||
109,
|
||||
97,
|
||||
115,
|
||||
107,
|
||||
]),
|
||||
],
|
||||
578365826: [
|
||||
new Uint8Array([
|
||||
67,
|
||||
58,
|
||||
12,
|
||||
110,
|
||||
111,
|
||||
116,
|
||||
105,
|
||||
102,
|
||||
105,
|
||||
99,
|
||||
97,
|
||||
116,
|
||||
105,
|
||||
111,
|
||||
110,
|
||||
50,
|
||||
51,
|
||||
47,
|
||||
97,
|
||||
112,
|
||||
105,
|
||||
47,
|
||||
118,
|
||||
49,
|
||||
47,
|
||||
123,
|
||||
110,
|
||||
111,
|
||||
116,
|
||||
105,
|
||||
102,
|
||||
105,
|
||||
99,
|
||||
97,
|
||||
116,
|
||||
105,
|
||||
111,
|
||||
110,
|
||||
46,
|
||||
110,
|
||||
97,
|
||||
109,
|
||||
101,
|
||||
61,
|
||||
117,
|
||||
115,
|
||||
101,
|
||||
114,
|
||||
115,
|
||||
47,
|
||||
42,
|
||||
47,
|
||||
110,
|
||||
111,
|
||||
116,
|
||||
105,
|
||||
102,
|
||||
105,
|
||||
99,
|
||||
97,
|
||||
116,
|
||||
105,
|
||||
111,
|
||||
110,
|
||||
115,
|
||||
47,
|
||||
42,
|
||||
125,
|
||||
]),
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
/** DeleteUserNotification deletes a notification. */
|
||||
deleteUserNotification: {
|
||||
name: "DeleteUserNotification",
|
||||
requestType: DeleteUserNotificationRequest,
|
||||
requestStream: false,
|
||||
responseType: Empty,
|
||||
responseStream: false,
|
||||
options: {
|
||||
_unknownFields: {
|
||||
8410: [new Uint8Array([4, 110, 97, 109, 101])],
|
||||
578365826: [
|
||||
new Uint8Array([
|
||||
40,
|
||||
42,
|
||||
38,
|
||||
47,
|
||||
97,
|
||||
112,
|
||||
105,
|
||||
47,
|
||||
118,
|
||||
49,
|
||||
47,
|
||||
123,
|
||||
110,
|
||||
97,
|
||||
109,
|
||||
101,
|
||||
61,
|
||||
117,
|
||||
115,
|
||||
101,
|
||||
114,
|
||||
115,
|
||||
47,
|
||||
42,
|
||||
47,
|
||||
110,
|
||||
111,
|
||||
116,
|
||||
105,
|
||||
102,
|
||||
105,
|
||||
99,
|
||||
97,
|
||||
116,
|
||||
105,
|
||||
111,
|
||||
110,
|
||||
115,
|
||||
47,
|
||||
42,
|
||||
125,
|
||||
]),
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue