From f2c8833cea2ac32956b852382daa0fc94de421c1 Mon Sep 17 00:00:00 2001
From: Yassine Bounekhla <56373201+rudream@users.noreply.github.com>
Date: Wed, 15 May 2024 21:26:58 +0200
Subject: [PATCH] implement listing notifications for a user with matching
(#39942)
---
api/client/client.go | 27 +
.../notifications/v1/notifications.pb.go | 246 +++--
.../v1/notifications_service.pb.go | 894 ++++--------------
.../v1/notifications_service_grpc.pb.go | 190 +---
.../notifications/v1/notifications.proto | 4 +-
.../v1/notifications_service.proto | 77 +-
api/types/constants.go | 9 +
lib/auth/authclient/clt.go | 38 +-
lib/auth/grpcserver.go | 14 +
lib/auth/helpers.go | 1 +
lib/auth/notification_test.go | 445 +++++++++
.../notifications/notificationsv1/service.go | 446 +++++++++
lib/cache/cache_test.go | 6 +-
lib/cache/collections.go | 4 +-
lib/services/local/events.go | 5 +-
lib/services/local/notifications.go | 36 +-
lib/services/local/notifications_test.go | 25 +-
lib/services/notifications.go | 5 +-
lib/services/notifications_cache.go | 5 +-
lib/services/notifications_cache_test.go | 120 +--
lib/services/notifications_test.go | 14 +-
21 files changed, 1448 insertions(+), 1163 deletions(-)
create mode 100644 lib/auth/notification_test.go
create mode 100644 lib/auth/notifications/notificationsv1/service.go
diff --git a/api/client/client.go b/api/client/client.go
index a8d7f17f671..5519f39df8e 100644
--- a/api/client/client.go
+++ b/api/client/client.go
@@ -76,6 +76,7 @@ import (
kubewaitingcontainerpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/kubewaitingcontainer/v1"
loginrulepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/loginrule/v1"
machineidv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1"
+ notificationsv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/notifications/v1"
oktapb "github.com/gravitational/teleport/api/gen/proto/go/teleport/okta/v1"
pluginspb "github.com/gravitational/teleport/api/gen/proto/go/teleport/plugins/v1"
presencepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/presence/v1"
@@ -111,6 +112,7 @@ type AuthServiceClient struct {
assist.AssistServiceClient
auditlogpb.AuditLogServiceClient
userpreferencespb.UserPreferencesServiceClient
+ notificationsv1pb.NotificationServiceClient
}
// Client is a gRPC Client that connects to a Teleport Auth server either
@@ -522,6 +524,7 @@ func (c *Client) dialGRPC(ctx context.Context, addr string) error {
AssistServiceClient: assist.NewAssistServiceClient(c.conn),
AuditLogServiceClient: auditlogpb.NewAuditLogServiceClient(c.conn),
UserPreferencesServiceClient: userpreferencespb.NewUserPreferencesServiceClient(c.conn),
+ NotificationServiceClient: notificationsv1pb.NewNotificationServiceClient(c.conn),
}
c.JoinServiceClient = NewJoinServiceClient(proto.NewJoinServiceClient(c.conn))
@@ -865,6 +868,11 @@ func (c *Client) WorkloadIdentityServiceClient() machineidv1pb.WorkloadIdentityS
return machineidv1pb.NewWorkloadIdentityServiceClient(c.conn)
}
+// NotificationServiceClient returns a notification service client that can be used to fetch notifications.
+func (c *Client) NotificationServiceClient() notificationsv1pb.NotificationServiceClient {
+ return notificationsv1pb.NewNotificationServiceClient(c.conn)
+}
+
// Ping gets basic info about the auth server.
func (c *Client) Ping(ctx context.Context) (proto.PingResponse, error) {
rsp, err := c.grpc.Ping(ctx, &proto.PingRequest{})
@@ -4899,6 +4907,25 @@ func (c *Client) UpsertUserPreferences(ctx context.Context, in *userpreferencesp
return nil
}
+// ListNotifications returns a paginated list of notifications for the user.
+// This includes global notifications which match the user, as well as user-specific notifications for the user.
+func (c *Client) ListNotifications(ctx context.Context, req *notificationsv1pb.ListNotificationsRequest) (*notificationsv1pb.ListNotificationsResponse, error) {
+ rsp, err := c.NotificationServiceClient().ListNotifications(ctx, req)
+ return rsp, trace.Wrap(err)
+}
+
+// UpsertUserNotificationState creates or updates a user notification state which records whether the user has clicked on or dismissed a notification.
+func (c *Client) UpsertUserNotificationState(ctx context.Context, req *notificationsv1pb.UpsertUserNotificationStateRequest) (*notificationsv1pb.UserNotificationState, error) {
+ rsp, err := c.NotificationServiceClient().UpsertUserNotificationState(ctx, req)
+ return rsp, trace.Wrap(err)
+}
+
+// UpsertUserLastSeenNotification creates or updates a user's last seen notification timestamp.
+func (c *Client) UpsertUserLastSeenNotification(ctx context.Context, req *notificationsv1pb.UpsertUserLastSeenNotificationRequest) (*notificationsv1pb.UserLastSeenNotification, error) {
+ rsp, err := c.NotificationServiceClient().UpsertUserLastSeenNotification(ctx, req)
+ return rsp, trace.Wrap(err)
+}
+
// ResourceUsageClient returns an unadorned Resource Usage service client,
// using the underlying Auth gRPC connection.
// Clients connecting to non-Enterprise clusters, or older Teleport versions,
diff --git a/api/gen/proto/go/teleport/notifications/v1/notifications.pb.go b/api/gen/proto/go/teleport/notifications/v1/notifications.pb.go
index 5cd61d6808c..bff1add294c 100644
--- a/api/gen/proto/go/teleport/notifications/v1/notifications.pb.go
+++ b/api/gen/proto/go/teleport/notifications/v1/notifications.pb.go
@@ -183,8 +183,6 @@ type NotificationSpec struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- // id is the UUID of the notification, in UUIDv7 format.
- Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
// created is when the notification was created, in UNIX time.
Created *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=created,proto3" json:"created,omitempty"`
// unscoped is whether the notification shouldn't be restricted to a specific audience. This is to prevent the potential future possibility that a user-specific notification contains information that the user should no longer be allowed to see. Default is true.
@@ -225,13 +223,6 @@ func (*NotificationSpec) Descriptor() ([]byte, []int) {
return file_teleport_notifications_v1_notifications_proto_rawDescGZIP(), []int{1}
}
-func (x *NotificationSpec) GetId() string {
- if x != nil {
- return x.Id
- }
- return ""
-}
-
func (x *NotificationSpec) GetCreated() *timestamppb.Timestamp {
if x != nil {
return x.Created
@@ -960,133 +951,132 @@ var file_teleport_notifications_v1_notifications_proto_rawDesc = []byte{
0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e,
0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e,
0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63,
- 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, 0x90, 0x01, 0x0a, 0x10, 0x4e, 0x6f, 0x74, 0x69, 0x66,
- 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x12, 0x0e, 0x0a, 0x02, 0x69,
- 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x34, 0x0a, 0x07, 0x63,
+ 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, 0x8a, 0x01, 0x0a, 0x10, 0x4e, 0x6f, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x12, 0x34, 0x0a, 0x07, 0x63,
0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x6e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x18, 0x03, 0x20,
0x01, 0x28, 0x08, 0x52, 0x08, 0x75, 0x6e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x12, 0x1a, 0x0a,
0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xde, 0x01, 0x0a, 0x12, 0x47, 0x6c,
- 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
- 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x75, 0x62, 0x5f, 0x6b, 0x69, 0x6e, 0x64,
- 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x4b, 0x69, 0x6e, 0x64, 0x12,
- 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74,
- 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x65,
- 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31,
- 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64,
- 0x61, 0x74, 0x61, 0x12, 0x45, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28,
- 0x0b, 0x32, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74,
- 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x6c,
- 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, 0xca, 0x02, 0x0a, 0x16, 0x47,
- 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x53, 0x70, 0x65, 0x63, 0x12, 0x51, 0x0a, 0x0e, 0x62, 0x79, 0x5f, 0x70, 0x65, 0x72, 0x6d,
- 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e,
- 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x79, 0x50, 0x65, 0x72, 0x6d,
- 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x0d, 0x62, 0x79, 0x50, 0x65, 0x72,
- 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3f, 0x0a, 0x08, 0x62, 0x79, 0x5f, 0x72,
- 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c,
- 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x79, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x48, 0x00,
- 0x52, 0x07, 0x62, 0x79, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x03, 0x61, 0x6c, 0x6c,
- 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x03, 0x61, 0x6c, 0x6c, 0x12, 0x30, 0x0a,
- 0x14, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69,
- 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x6d, 0x61, 0x74,
- 0x63, 0x68, 0x41, 0x6c, 0x6c, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12,
- 0x4b, 0x0a, 0x0c, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18,
- 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
- 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76,
- 0x31, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c,
- 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07,
- 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x22, 0x4f, 0x0a, 0x0d, 0x42, 0x79, 0x50, 0x65, 0x72,
- 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3e, 0x0a, 0x0f, 0x72, 0x6f, 0x6c, 0x65,
- 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
- 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x43, 0x6f,
- 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x0e, 0x72, 0x6f, 0x6c, 0x65, 0x43, 0x6f,
- 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x1f, 0x0a, 0x07, 0x42, 0x79, 0x52, 0x6f,
- 0x6c, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03,
- 0x28, 0x09, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x22, 0xb4, 0x02, 0x0a, 0x15, 0x55, 0x73,
- 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74,
- 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x75, 0x62, 0x5f, 0x6b,
- 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x4b, 0x69,
- 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x08,
- 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c,
- 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
- 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65,
- 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x48, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x05,
- 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e,
+ 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x52,
+ 0x02, 0x69, 0x64, 0x22, 0xde, 0x01, 0x0a, 0x12, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f,
+ 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69,
+ 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x19,
+ 0x0a, 0x08, 0x73, 0x75, 0x62, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x07, 0x73, 0x75, 0x62, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72,
+ 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73,
+ 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18,
+ 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
+ 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64,
+ 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x45, 0x0a,
+ 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x74, 0x65,
+ 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f,
+ 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04,
+ 0x73, 0x70, 0x65, 0x63, 0x22, 0xca, 0x02, 0x0a, 0x16, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e,
+ 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x12,
+ 0x51, 0x0a, 0x0e, 0x62, 0x79, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e,
+ 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f,
+ 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x79, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e,
+ 0x73, 0x48, 0x00, 0x52, 0x0d, 0x62, 0x79, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f,
+ 0x6e, 0x73, 0x12, 0x3f, 0x0a, 0x08, 0x62, 0x79, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e,
0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31,
- 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63,
- 0x12, 0x4e, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x36, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69,
- 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65,
- 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61,
- 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
- 0x22, 0x44, 0x0a, 0x19, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x70, 0x65, 0x63, 0x12, 0x27, 0x0a,
- 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64,
- 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x7a, 0x0a, 0x1b, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f,
- 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53,
- 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x5b, 0x0a, 0x12, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x0e, 0x32, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74,
- 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f,
- 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52,
- 0x11, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61,
- 0x74, 0x65, 0x22, 0xc9, 0x02, 0x0a, 0x18, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53,
- 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12,
- 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b,
- 0x69, 0x6e, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x75, 0x62, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18,
- 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x18,
- 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61,
- 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x65, 0x6c,
- 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
- 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
- 0x74, 0x61, 0x12, 0x4b, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x37, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69,
- 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65,
- 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x12,
- 0x51, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32,
- 0x39, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66,
- 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72,
+ 0x2e, 0x42, 0x79, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x48, 0x00, 0x52, 0x07, 0x62, 0x79, 0x52, 0x6f,
+ 0x6c, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x03, 0x61, 0x6c, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
+ 0x48, 0x00, 0x52, 0x03, 0x61, 0x6c, 0x6c, 0x12, 0x30, 0x0a, 0x14, 0x6d, 0x61, 0x74, 0x63, 0x68,
+ 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18,
+ 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x41, 0x6c, 0x6c, 0x43,
+ 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x4b, 0x0a, 0x0c, 0x6e, 0x6f, 0x74,
+ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x74, 0x69,
+ 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65,
+ 0x72, 0x22, 0x4f, 0x0a, 0x0d, 0x42, 0x79, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f,
+ 0x6e, 0x73, 0x12, 0x3e, 0x0a, 0x0f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x79,
+ 0x70, 0x65, 0x73, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f,
+ 0x6e, 0x73, 0x52, 0x0e, 0x72, 0x6f, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f,
+ 0x6e, 0x73, 0x22, 0x1f, 0x0a, 0x07, 0x42, 0x79, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x14, 0x0a,
+ 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x6f,
+ 0x6c, 0x65, 0x73, 0x22, 0xb4, 0x02, 0x0a, 0x15, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69,
+ 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a,
+ 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e,
+ 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x75, 0x62, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07,
+ 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76,
+ 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
+ 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70,
+ 0x6f, 0x72, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65,
+ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+ 0x12, 0x48, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34,
+ 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4e,
+ 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x12, 0x4e, 0x0a, 0x06, 0x73, 0x74,
+ 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x74, 0x65, 0x6c,
+ 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74,
+ 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x44, 0x0a, 0x19, 0x55, 0x73,
+ 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x53, 0x70, 0x65, 0x63, 0x12, 0x27, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x0e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64,
+ 0x22, 0x7a, 0x0a, 0x1b, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12,
+ 0x5b, 0x0a, 0x12, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
+ 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x74, 0x65,
+ 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x11, 0x6e, 0x6f, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0xc9, 0x02, 0x0a,
+ 0x18, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74,
+ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e,
+ 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x19, 0x0a,
+ 0x08, 0x73, 0x75, 0x62, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x07, 0x73, 0x75, 0x62, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73,
+ 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
+ 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e,
+ 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
+ 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x4b, 0x0a, 0x04,
+ 0x73, 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x74, 0x65, 0x6c,
+ 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53,
+ 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53,
+ 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x12, 0x51, 0x0a, 0x06, 0x73, 0x74, 0x61,
+ 0x74, 0x75, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x74, 0x65, 0x6c, 0x65,
+ 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65,
+ 0x65, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74,
+ 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4a, 0x04, 0x08, 0x06,
+ 0x10, 0x07, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x1e, 0x0a, 0x1c, 0x55, 0x73, 0x65, 0x72,
0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74,
- 0x75, 0x73, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x1e,
- 0x0a, 0x1c, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f,
- 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x22, 0x62,
- 0x0a, 0x1e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f,
- 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
- 0x12, 0x40, 0x0a, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x74, 0x69,
- 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
- 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73,
- 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x54, 0x69,
- 0x6d, 0x65, 0x2a, 0x79, 0x0a, 0x11, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22, 0x0a, 0x1e, 0x4e, 0x4f, 0x54, 0x49, 0x46,
- 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e,
- 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x4e,
- 0x4f, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54,
- 0x45, 0x5f, 0x43, 0x4c, 0x49, 0x43, 0x4b, 0x45, 0x44, 0x10, 0x01, 0x12, 0x20, 0x0a, 0x1c, 0x4e,
- 0x4f, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54,
- 0x45, 0x5f, 0x44, 0x49, 0x53, 0x4d, 0x49, 0x53, 0x53, 0x45, 0x44, 0x10, 0x02, 0x42, 0x5e, 0x5a,
- 0x5c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76,
- 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f,
- 0x72, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
- 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6e, 0x6f, 0x74,
- 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x6e, 0x6f,
- 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x76, 0x31, 0x62, 0x06, 0x70,
- 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x22, 0x62, 0x0a, 0x1e, 0x55, 0x73, 0x65, 0x72,
+ 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x40, 0x0a, 0x0e, 0x6c, 0x61,
+ 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c,
+ 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x2a, 0x79, 0x0a, 0x11,
+ 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x12, 0x22, 0x0a, 0x1e, 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f,
+ 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46,
+ 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x49, 0x43,
+ 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x43, 0x4c, 0x49, 0x43,
+ 0x4b, 0x45, 0x44, 0x10, 0x01, 0x12, 0x20, 0x0a, 0x1c, 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x49, 0x43,
+ 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x49, 0x53, 0x4d,
+ 0x49, 0x53, 0x53, 0x45, 0x44, 0x10, 0x02, 0x42, 0x5e, 0x5a, 0x5c, 0x67, 0x69, 0x74, 0x68, 0x75,
+ 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x70, 0x69,
+ 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65,
+ 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/api/gen/proto/go/teleport/notifications/v1/notifications_service.pb.go b/api/gen/proto/go/teleport/notifications/v1/notifications_service.pb.go
index 452bc49069a..af5b92c2b3d 100644
--- a/api/gen/proto/go/teleport/notifications/v1/notifications_service.pb.go
+++ b/api/gen/proto/go/teleport/notifications/v1/notifications_service.pb.go
@@ -27,6 +27,7 @@ import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
emptypb "google.golang.org/protobuf/types/known/emptypb"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
sync "sync"
)
@@ -154,22 +155,20 @@ func (x *DeleteUserNotificationRequest) GetNotificationId() string {
return ""
}
-// ListUserNotificationsRequest is the request for listing a user's notifications, which include user-specific ones as well as global notifications that match them.
-type ListUserNotificationsRequest struct {
+// ListNotificationsRequest is the request for listing a user's notifications.
+type ListNotificationsRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- // username is the username of the user the notifications to list are for.
- Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
// page_size is the size of the page to return.
- PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
+ PageSize int32 `protobuf:"varint,1,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
// page_token is the next_page_token value returned from a previous ListUserNotifications request, if any.
- PageToken string `protobuf:"bytes,3,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"`
+ PageToken string `protobuf:"bytes,2,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"`
}
-func (x *ListUserNotificationsRequest) Reset() {
- *x = ListUserNotificationsRequest{}
+func (x *ListNotificationsRequest) Reset() {
+ *x = ListNotificationsRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -177,13 +176,13 @@ func (x *ListUserNotificationsRequest) Reset() {
}
}
-func (x *ListUserNotificationsRequest) String() string {
+func (x *ListNotificationsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
-func (*ListUserNotificationsRequest) ProtoMessage() {}
+func (*ListNotificationsRequest) ProtoMessage() {}
-func (x *ListUserNotificationsRequest) ProtoReflect() protoreflect.Message {
+func (x *ListNotificationsRequest) ProtoReflect() protoreflect.Message {
mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -195,46 +194,41 @@ func (x *ListUserNotificationsRequest) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x)
}
-// Deprecated: Use ListUserNotificationsRequest.ProtoReflect.Descriptor instead.
-func (*ListUserNotificationsRequest) Descriptor() ([]byte, []int) {
+// Deprecated: Use ListNotificationsRequest.ProtoReflect.Descriptor instead.
+func (*ListNotificationsRequest) Descriptor() ([]byte, []int) {
return file_teleport_notifications_v1_notifications_service_proto_rawDescGZIP(), []int{2}
}
-func (x *ListUserNotificationsRequest) GetUsername() string {
- if x != nil {
- return x.Username
- }
- return ""
-}
-
-func (x *ListUserNotificationsRequest) GetPageSize() int32 {
+func (x *ListNotificationsRequest) GetPageSize() int32 {
if x != nil {
return x.PageSize
}
return 0
}
-func (x *ListUserNotificationsRequest) GetPageToken() string {
+func (x *ListNotificationsRequest) GetPageToken() string {
if x != nil {
return x.PageToken
}
return ""
}
-// ListUserNotificationsResponse is the response from listing a user's user-specific notifications.
-type ListUserNotificationsResponse struct {
+// ListNotificationsResponse is the response from listing a user's notifications.
+type ListNotificationsResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// notifications is the notifications returned.
Notifications []*Notification `protobuf:"bytes,1,rep,name=notifications,proto3" json:"notifications,omitempty"`
- // next_page_token is the token to retrieve the next page of results, this will be empty if there are no more results.
- NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"`
+ // next_page_token contains the next page token to use as the start key for the next page of notifications.
+ NextPageToken string `protobuf:"bytes,3,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"`
+ // user_last_seen_notification_timestamp is the timestamp of the last notification the user has seen.
+ UserLastSeenNotificationTimestamp *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=user_last_seen_notification_timestamp,json=userLastSeenNotificationTimestamp,proto3" json:"user_last_seen_notification_timestamp,omitempty"`
}
-func (x *ListUserNotificationsResponse) Reset() {
- *x = ListUserNotificationsResponse{}
+func (x *ListNotificationsResponse) Reset() {
+ *x = ListNotificationsResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -242,13 +236,13 @@ func (x *ListUserNotificationsResponse) Reset() {
}
}
-func (x *ListUserNotificationsResponse) String() string {
+func (x *ListNotificationsResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
-func (*ListUserNotificationsResponse) ProtoMessage() {}
+func (*ListNotificationsResponse) ProtoMessage() {}
-func (x *ListUserNotificationsResponse) ProtoReflect() protoreflect.Message {
+func (x *ListNotificationsResponse) ProtoReflect() protoreflect.Message {
mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -260,25 +254,32 @@ func (x *ListUserNotificationsResponse) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x)
}
-// Deprecated: Use ListUserNotificationsResponse.ProtoReflect.Descriptor instead.
-func (*ListUserNotificationsResponse) Descriptor() ([]byte, []int) {
+// Deprecated: Use ListNotificationsResponse.ProtoReflect.Descriptor instead.
+func (*ListNotificationsResponse) Descriptor() ([]byte, []int) {
return file_teleport_notifications_v1_notifications_service_proto_rawDescGZIP(), []int{3}
}
-func (x *ListUserNotificationsResponse) GetNotifications() []*Notification {
+func (x *ListNotificationsResponse) GetNotifications() []*Notification {
if x != nil {
return x.Notifications
}
return nil
}
-func (x *ListUserNotificationsResponse) GetNextPageToken() string {
+func (x *ListNotificationsResponse) GetNextPageToken() string {
if x != nil {
return x.NextPageToken
}
return ""
}
+func (x *ListNotificationsResponse) GetUserLastSeenNotificationTimestamp() *timestamppb.Timestamp {
+ if x != nil {
+ return x.UserLastSeenNotificationTimestamp
+ }
+ return nil
+}
+
// CreateGlobalNotificationRequest is the request for creating a global notification.
type CreateGlobalNotificationRequest struct {
state protoimpl.MessageState
@@ -435,278 +436,6 @@ func (x *UpsertUserNotificationStateRequest) GetUserNotificationState() *UserNot
return nil
}
-// UpdateUserNotificationStateRequest is the request for updating a user notification state.
-type UpdateUserNotificationStateRequest struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // username is the username of the user.
- Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
- // user_notification_state is the updated user notification state.
- UserNotificationState *UserNotificationState `protobuf:"bytes,2,opt,name=user_notification_state,json=userNotificationState,proto3" json:"user_notification_state,omitempty"`
-}
-
-func (x *UpdateUserNotificationStateRequest) Reset() {
- *x = UpdateUserNotificationStateRequest{}
- if protoimpl.UnsafeEnabled {
- mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[7]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *UpdateUserNotificationStateRequest) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*UpdateUserNotificationStateRequest) ProtoMessage() {}
-
-func (x *UpdateUserNotificationStateRequest) ProtoReflect() protoreflect.Message {
- mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[7]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use UpdateUserNotificationStateRequest.ProtoReflect.Descriptor instead.
-func (*UpdateUserNotificationStateRequest) Descriptor() ([]byte, []int) {
- return file_teleport_notifications_v1_notifications_service_proto_rawDescGZIP(), []int{7}
-}
-
-func (x *UpdateUserNotificationStateRequest) GetUsername() string {
- if x != nil {
- return x.Username
- }
- return ""
-}
-
-func (x *UpdateUserNotificationStateRequest) GetUserNotificationState() *UserNotificationState {
- if x != nil {
- return x.UserNotificationState
- }
- return nil
-}
-
-// DeleteUserNotificationState is the request for deleting a user notification state.
-type DeleteUserNotificationStateRequest struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // username is the username of the user.
- Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
- // notification_id is the ID of the notification the notifiation state to delete is for.
- NotificationId string `protobuf:"bytes,2,opt,name=notification_id,json=notificationId,proto3" json:"notification_id,omitempty"`
-}
-
-func (x *DeleteUserNotificationStateRequest) Reset() {
- *x = DeleteUserNotificationStateRequest{}
- if protoimpl.UnsafeEnabled {
- mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[8]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *DeleteUserNotificationStateRequest) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*DeleteUserNotificationStateRequest) ProtoMessage() {}
-
-func (x *DeleteUserNotificationStateRequest) ProtoReflect() protoreflect.Message {
- mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[8]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use DeleteUserNotificationStateRequest.ProtoReflect.Descriptor instead.
-func (*DeleteUserNotificationStateRequest) Descriptor() ([]byte, []int) {
- return file_teleport_notifications_v1_notifications_service_proto_rawDescGZIP(), []int{8}
-}
-
-func (x *DeleteUserNotificationStateRequest) GetUsername() string {
- if x != nil {
- return x.Username
- }
- return ""
-}
-
-func (x *DeleteUserNotificationStateRequest) GetNotificationId() string {
- if x != nil {
- return x.NotificationId
- }
- return ""
-}
-
-// ListUserNotificationStatesRequest is the request for listing a user's notification states.
-type ListUserNotificationStatesRequest struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // username is the username of the user.
- Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
-}
-
-func (x *ListUserNotificationStatesRequest) Reset() {
- *x = ListUserNotificationStatesRequest{}
- if protoimpl.UnsafeEnabled {
- mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[9]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *ListUserNotificationStatesRequest) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*ListUserNotificationStatesRequest) ProtoMessage() {}
-
-func (x *ListUserNotificationStatesRequest) ProtoReflect() protoreflect.Message {
- mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[9]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use ListUserNotificationStatesRequest.ProtoReflect.Descriptor instead.
-func (*ListUserNotificationStatesRequest) Descriptor() ([]byte, []int) {
- return file_teleport_notifications_v1_notifications_service_proto_rawDescGZIP(), []int{9}
-}
-
-func (x *ListUserNotificationStatesRequest) GetUsername() string {
- if x != nil {
- return x.Username
- }
- return ""
-}
-
-// ListUserNotificationStatesResponse is the response from listing a user's notification states.
-type ListUserNotificationStatesResponse struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // notification_states is the user notification state items returned.
- NotificationStates []*UserNotificationState `protobuf:"bytes,1,rep,name=notification_states,json=notificationStates,proto3" json:"notification_states,omitempty"`
- // next_page_token is the token to retrieve the next page of results, this will be empty if there are no more results.
- NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"`
-}
-
-func (x *ListUserNotificationStatesResponse) Reset() {
- *x = ListUserNotificationStatesResponse{}
- if protoimpl.UnsafeEnabled {
- mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[10]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *ListUserNotificationStatesResponse) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*ListUserNotificationStatesResponse) ProtoMessage() {}
-
-func (x *ListUserNotificationStatesResponse) ProtoReflect() protoreflect.Message {
- mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[10]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use ListUserNotificationStatesResponse.ProtoReflect.Descriptor instead.
-func (*ListUserNotificationStatesResponse) Descriptor() ([]byte, []int) {
- return file_teleport_notifications_v1_notifications_service_proto_rawDescGZIP(), []int{10}
-}
-
-func (x *ListUserNotificationStatesResponse) GetNotificationStates() []*UserNotificationState {
- if x != nil {
- return x.NotificationStates
- }
- return nil
-}
-
-func (x *ListUserNotificationStatesResponse) GetNextPageToken() string {
- if x != nil {
- return x.NextPageToken
- }
- return ""
-}
-
-// GetUserLastSeenNotificationRequest is the request for getting a user's last seen notification.
-type GetUserLastSeenNotificationRequest struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // username is the username of the user.
- Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
-}
-
-func (x *GetUserLastSeenNotificationRequest) Reset() {
- *x = GetUserLastSeenNotificationRequest{}
- if protoimpl.UnsafeEnabled {
- mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[11]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *GetUserLastSeenNotificationRequest) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GetUserLastSeenNotificationRequest) ProtoMessage() {}
-
-func (x *GetUserLastSeenNotificationRequest) ProtoReflect() protoreflect.Message {
- mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[11]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GetUserLastSeenNotificationRequest.ProtoReflect.Descriptor instead.
-func (*GetUserLastSeenNotificationRequest) Descriptor() ([]byte, []int) {
- return file_teleport_notifications_v1_notifications_service_proto_rawDescGZIP(), []int{11}
-}
-
-func (x *GetUserLastSeenNotificationRequest) GetUsername() string {
- if x != nil {
- return x.Username
- }
- return ""
-}
-
// UpsertUserLastSeenNotificationRequest is the request for creating or updating a user's last seen notification.
type UpsertUserLastSeenNotificationRequest struct {
state protoimpl.MessageState
@@ -715,14 +444,14 @@ type UpsertUserLastSeenNotificationRequest struct {
// username is the username of the user.
Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
- // user_notification_state is the udpated user last seen notification item.
+ // user_notification_state is the updated user last seen notification item.
UserLastSeenNotification *UserLastSeenNotification `protobuf:"bytes,2,opt,name=user_last_seen_notification,json=userLastSeenNotification,proto3" json:"user_last_seen_notification,omitempty"`
}
func (x *UpsertUserLastSeenNotificationRequest) Reset() {
*x = UpsertUserLastSeenNotificationRequest{}
if protoimpl.UnsafeEnabled {
- mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[12]
+ mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -735,7 +464,7 @@ func (x *UpsertUserLastSeenNotificationRequest) String() string {
func (*UpsertUserLastSeenNotificationRequest) ProtoMessage() {}
func (x *UpsertUserLastSeenNotificationRequest) ProtoReflect() protoreflect.Message {
- mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[12]
+ mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -748,7 +477,7 @@ func (x *UpsertUserLastSeenNotificationRequest) ProtoReflect() protoreflect.Mess
// Deprecated: Use UpsertUserLastSeenNotificationRequest.ProtoReflect.Descriptor instead.
func (*UpsertUserLastSeenNotificationRequest) Descriptor() ([]byte, []int) {
- return file_teleport_notifications_v1_notifications_service_proto_rawDescGZIP(), []int{12}
+ return file_teleport_notifications_v1_notifications_service_proto_rawDescGZIP(), []int{7}
}
func (x *UpsertUserLastSeenNotificationRequest) GetUsername() string {
@@ -765,55 +494,6 @@ func (x *UpsertUserLastSeenNotificationRequest) GetUserLastSeenNotification() *U
return nil
}
-// DeleteUserLastSeenNotificationRequest is the request for deleting a user's last seen notification.
-type DeleteUserLastSeenNotificationRequest struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- // username is the username of the user.
- Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
-}
-
-func (x *DeleteUserLastSeenNotificationRequest) Reset() {
- *x = DeleteUserLastSeenNotificationRequest{}
- if protoimpl.UnsafeEnabled {
- mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[13]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
-}
-
-func (x *DeleteUserLastSeenNotificationRequest) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*DeleteUserLastSeenNotificationRequest) ProtoMessage() {}
-
-func (x *DeleteUserLastSeenNotificationRequest) ProtoReflect() protoreflect.Message {
- mi := &file_teleport_notifications_v1_notifications_service_proto_msgTypes[13]
- if protoimpl.UnsafeEnabled && x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use DeleteUserLastSeenNotificationRequest.ProtoReflect.Descriptor instead.
-func (*DeleteUserLastSeenNotificationRequest) Descriptor() ([]byte, []int) {
- return file_teleport_notifications_v1_notifications_service_proto_rawDescGZIP(), []int{13}
-}
-
-func (x *DeleteUserLastSeenNotificationRequest) GetUsername() string {
- if x != nil {
- return x.Username
- }
- return ""
-}
-
var File_teleport_notifications_v1_notifications_service_proto protoreflect.FileDescriptor
var file_teleport_notifications_v1_notifications_service_proto_rawDesc = []byte{
@@ -824,218 +504,148 @@ var file_teleport_notifications_v1_notifications_service_proto_rawDesc = []byte{
0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
0x76, 0x31, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,
- 0x2d, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66,
- 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x88,
- 0x01, 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74,
- 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
- 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4b, 0x0a, 0x0c,
- 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01,
- 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f,
- 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4e,
- 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x6e, 0x6f, 0x74,
- 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x64, 0x0a, 0x1d, 0x44, 0x65, 0x6c,
- 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73,
- 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73,
- 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x0e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22,
- 0x76, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66,
- 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
- 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70,
- 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08,
- 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65,
- 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61,
- 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x96, 0x01, 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x74,
- 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0d, 0x6e, 0x6f, 0x74,
- 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
- 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69,
- 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x74,
- 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x6e, 0x6f, 0x74, 0x69, 0x66,
- 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74,
- 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
- 0x22, 0x81, 0x01, 0x0a, 0x1f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x6c, 0x6f, 0x62, 0x61,
- 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71,
- 0x75, 0x65, 0x73, 0x74, 0x12, 0x5e, 0x0a, 0x13, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x6e,
- 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74,
- 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x6c,
- 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x52, 0x12, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x4a, 0x0a, 0x1f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x6c,
- 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x66,
- 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x0e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64,
- 0x22, 0xaa, 0x01, 0x0a, 0x22, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4e,
- 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65,
- 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e,
- 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e,
- 0x61, 0x6d, 0x65, 0x12, 0x68, 0x0a, 0x17, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6e, 0x6f, 0x74, 0x69,
- 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02,
- 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e,
- 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31,
- 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x15, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69,
- 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0xaa, 0x01,
- 0x0a, 0x22, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69,
- 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71,
- 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65,
- 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65,
- 0x12, 0x68, 0x0a, 0x17, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x0b, 0x32, 0x30, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74,
- 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73,
- 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74,
- 0x61, 0x74, 0x65, 0x52, 0x15, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x69, 0x0a, 0x22, 0x44, 0x65,
+ 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+ 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x1a, 0x2d, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x74, 0x69,
+ 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
+ 0x88, 0x01, 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f,
+ 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4b, 0x0a,
+ 0x0c, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e,
+ 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e,
+ 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x6e, 0x6f,
+ 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x64, 0x0a, 0x1d, 0x44, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
- 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f,
- 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18,
- 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x3f, 0x0a, 0x21, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65,
- 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61,
- 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73,
- 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73,
- 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xaf, 0x01, 0x0a, 0x22, 0x4c, 0x69, 0x73, 0x74, 0x55,
- 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53,
- 0x74, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x61, 0x0a,
- 0x13, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74,
- 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x74, 0x65, 0x6c,
- 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66,
- 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x12, 0x6e, 0x6f,
- 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73,
- 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f,
- 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50,
- 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x40, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x55,
- 0x73, 0x65, 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66,
- 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a,
- 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xb7, 0x01, 0x0a, 0x25, 0x55,
- 0x70, 0x73, 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65,
- 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71,
- 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65,
- 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65,
- 0x12, 0x72, 0x0a, 0x1b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65,
- 0x65, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18,
- 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
- 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76,
- 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f,
- 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x18, 0x75, 0x73, 0x65, 0x72,
- 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x43, 0x0a, 0x25, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73,
- 0x65, 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a,
- 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x32, 0xd0, 0x0b, 0x0a, 0x13, 0x4e, 0x6f,
- 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
- 0x65, 0x12, 0x7b, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e,
- 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x2e, 0x74, 0x65,
- 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73,
- 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65,
- 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
- 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76,
- 0x31, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6a,
- 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69,
- 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70,
- 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e,
+ 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75,
+ 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75,
+ 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x0e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64,
+ 0x22, 0x56, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09,
+ 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
+ 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67,
+ 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70,
+ 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x80, 0x02, 0x0a, 0x19, 0x4c, 0x69, 0x73,
+ 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0d, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e,
+ 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61,
+ 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d,
+ 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x6c, 0x0a,
+ 0x25, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f,
+ 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d,
+ 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
+ 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x21, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x61,
+ 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x81, 0x01, 0x0a, 0x1f,
+ 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69,
+ 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+ 0x5e, 0x0a, 0x13, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74,
+ 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e,
+ 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x12, 0x67, 0x6c, 0x6f,
+ 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22,
+ 0x4a, 0x0a, 0x1f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e,
0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65,
- 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
- 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x85, 0x01, 0x0a, 0x18, 0x43,
- 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66,
+ 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6e, 0x6f, 0x74,
+ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xaa, 0x01, 0x0a, 0x22,
+ 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x68,
+ 0x0a, 0x17, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x30, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72,
+ 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x52, 0x15, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0xb7, 0x01, 0x0a, 0x25, 0x55, 0x70, 0x73,
+ 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e,
+ 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x72,
+ 0x0a, 0x1b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e,
+ 0x5f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e,
+ 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e,
+ 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74, 0x69,
+ 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x18, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x61,
+ 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x32, 0xa1, 0x07, 0x0a, 0x13, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7b, 0x0a, 0x16, 0x43, 0x72,
+ 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e,
+ 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31,
+ 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27,
+ 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6a, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74,
+ 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x12, 0x38, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74,
+ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65,
+ 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,
+ 0x70, 0x74, 0x79, 0x12, 0x85, 0x01, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x6c,
+ 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x12, 0x3a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69,
+ 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65,
+ 0x61, 0x74, 0x65, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x74,
+ 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e,
+ 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6e, 0x0a, 0x18, 0x44,
+ 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66,
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f,
0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
- 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
+ 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75,
- 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e,
- 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e,
- 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x12, 0x6e, 0x0a, 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x6c, 0x6f, 0x62,
- 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a,
- 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74,
- 0x65, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f,
- 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70,
- 0x74, 0x79, 0x12, 0x8a, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4e,
- 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x37, 0x2e, 0x74,
- 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65,
- 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65,
- 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
+ 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x7e, 0x0a, 0x11, 0x4c,
+ 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x12, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69,
+ 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73,
+ 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76,
- 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
- 0x8e, 0x01, 0x0a, 0x1b, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f,
- 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12,
- 0x3d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66,
+ 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x8e, 0x01, 0x0a, 0x1b,
+ 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3d, 0x2e, 0x74, 0x65,
+ 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x55, 0x73,
+ 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x74, 0x65, 0x6c,
+ 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x97, 0x01, 0x0a,
+ 0x1e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53,
+ 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12,
+ 0x40, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66,
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x73, 0x65,
- 0x72, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30,
- 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4e,
- 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65,
- 0x12, 0x74, 0x0a, 0x1b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f,
- 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12,
- 0x3d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66,
- 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65,
- 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16,
- 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
- 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x99, 0x01, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x55,
- 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53,
- 0x74, 0x61, 0x74, 0x65, 0x73, 0x12, 0x3c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
- 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76,
- 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75,
- 0x65, 0x73, 0x74, 0x1a, 0x3d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e,
- 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e,
- 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
- 0x73, 0x65, 0x12, 0x91, 0x01, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61,
- 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x12, 0x3d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f,
- 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47,
- 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f,
+ 0x72, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f,
0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74,
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73,
0x65, 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x97, 0x01, 0x0a, 0x1e, 0x55, 0x70, 0x73, 0x65, 0x72,
- 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74,
- 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x2e, 0x74, 0x65, 0x6c, 0x65,
- 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, 0x72,
- 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x74, 0x65,
- 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x73, 0x74,
- 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x12, 0x7a, 0x0a, 0x1e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61,
- 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x12, 0x40, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f,
- 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44,
- 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65,
- 0x6e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71,
- 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x5e, 0x5a, 0x5c,
- 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69,
- 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72,
- 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
- 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6e, 0x6f, 0x74, 0x69,
- 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x6e, 0x6f, 0x74,
- 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x33,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x5e, 0x5a, 0x5c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f,
+ 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c,
+ 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x73, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -1050,63 +660,49 @@ func file_teleport_notifications_v1_notifications_service_proto_rawDescGZIP() []
return file_teleport_notifications_v1_notifications_service_proto_rawDescData
}
-var file_teleport_notifications_v1_notifications_service_proto_msgTypes = make([]protoimpl.MessageInfo, 14)
+var file_teleport_notifications_v1_notifications_service_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
var file_teleport_notifications_v1_notifications_service_proto_goTypes = []interface{}{
(*CreateUserNotificationRequest)(nil), // 0: teleport.notifications.v1.CreateUserNotificationRequest
(*DeleteUserNotificationRequest)(nil), // 1: teleport.notifications.v1.DeleteUserNotificationRequest
- (*ListUserNotificationsRequest)(nil), // 2: teleport.notifications.v1.ListUserNotificationsRequest
- (*ListUserNotificationsResponse)(nil), // 3: teleport.notifications.v1.ListUserNotificationsResponse
+ (*ListNotificationsRequest)(nil), // 2: teleport.notifications.v1.ListNotificationsRequest
+ (*ListNotificationsResponse)(nil), // 3: teleport.notifications.v1.ListNotificationsResponse
(*CreateGlobalNotificationRequest)(nil), // 4: teleport.notifications.v1.CreateGlobalNotificationRequest
(*DeleteGlobalNotificationRequest)(nil), // 5: teleport.notifications.v1.DeleteGlobalNotificationRequest
(*UpsertUserNotificationStateRequest)(nil), // 6: teleport.notifications.v1.UpsertUserNotificationStateRequest
- (*UpdateUserNotificationStateRequest)(nil), // 7: teleport.notifications.v1.UpdateUserNotificationStateRequest
- (*DeleteUserNotificationStateRequest)(nil), // 8: teleport.notifications.v1.DeleteUserNotificationStateRequest
- (*ListUserNotificationStatesRequest)(nil), // 9: teleport.notifications.v1.ListUserNotificationStatesRequest
- (*ListUserNotificationStatesResponse)(nil), // 10: teleport.notifications.v1.ListUserNotificationStatesResponse
- (*GetUserLastSeenNotificationRequest)(nil), // 11: teleport.notifications.v1.GetUserLastSeenNotificationRequest
- (*UpsertUserLastSeenNotificationRequest)(nil), // 12: teleport.notifications.v1.UpsertUserLastSeenNotificationRequest
- (*DeleteUserLastSeenNotificationRequest)(nil), // 13: teleport.notifications.v1.DeleteUserLastSeenNotificationRequest
- (*Notification)(nil), // 14: teleport.notifications.v1.Notification
- (*GlobalNotification)(nil), // 15: teleport.notifications.v1.GlobalNotification
- (*UserNotificationState)(nil), // 16: teleport.notifications.v1.UserNotificationState
- (*UserLastSeenNotification)(nil), // 17: teleport.notifications.v1.UserLastSeenNotification
- (*emptypb.Empty)(nil), // 18: google.protobuf.Empty
+ (*UpsertUserLastSeenNotificationRequest)(nil), // 7: teleport.notifications.v1.UpsertUserLastSeenNotificationRequest
+ (*Notification)(nil), // 8: teleport.notifications.v1.Notification
+ (*timestamppb.Timestamp)(nil), // 9: google.protobuf.Timestamp
+ (*GlobalNotification)(nil), // 10: teleport.notifications.v1.GlobalNotification
+ (*UserNotificationState)(nil), // 11: teleport.notifications.v1.UserNotificationState
+ (*UserLastSeenNotification)(nil), // 12: teleport.notifications.v1.UserLastSeenNotification
+ (*emptypb.Empty)(nil), // 13: google.protobuf.Empty
}
var file_teleport_notifications_v1_notifications_service_proto_depIdxs = []int32{
- 14, // 0: teleport.notifications.v1.CreateUserNotificationRequest.notification:type_name -> teleport.notifications.v1.Notification
- 14, // 1: teleport.notifications.v1.ListUserNotificationsResponse.notifications:type_name -> teleport.notifications.v1.Notification
- 15, // 2: teleport.notifications.v1.CreateGlobalNotificationRequest.global_notification:type_name -> teleport.notifications.v1.GlobalNotification
- 16, // 3: teleport.notifications.v1.UpsertUserNotificationStateRequest.user_notification_state:type_name -> teleport.notifications.v1.UserNotificationState
- 16, // 4: teleport.notifications.v1.UpdateUserNotificationStateRequest.user_notification_state:type_name -> teleport.notifications.v1.UserNotificationState
- 16, // 5: teleport.notifications.v1.ListUserNotificationStatesResponse.notification_states:type_name -> teleport.notifications.v1.UserNotificationState
- 17, // 6: teleport.notifications.v1.UpsertUserLastSeenNotificationRequest.user_last_seen_notification:type_name -> teleport.notifications.v1.UserLastSeenNotification
- 0, // 7: teleport.notifications.v1.NotificationService.CreateUserNotification:input_type -> teleport.notifications.v1.CreateUserNotificationRequest
- 1, // 8: teleport.notifications.v1.NotificationService.DeleteUserNotification:input_type -> teleport.notifications.v1.DeleteUserNotificationRequest
- 4, // 9: teleport.notifications.v1.NotificationService.CreateGlobalNotification:input_type -> teleport.notifications.v1.CreateGlobalNotificationRequest
- 5, // 10: teleport.notifications.v1.NotificationService.DeleteGlobalNotification:input_type -> teleport.notifications.v1.DeleteGlobalNotificationRequest
- 2, // 11: teleport.notifications.v1.NotificationService.ListUserNotifications:input_type -> teleport.notifications.v1.ListUserNotificationsRequest
- 6, // 12: teleport.notifications.v1.NotificationService.UpsertUserNotificationState:input_type -> teleport.notifications.v1.UpsertUserNotificationStateRequest
- 8, // 13: teleport.notifications.v1.NotificationService.DeleteUserNotificationState:input_type -> teleport.notifications.v1.DeleteUserNotificationStateRequest
- 9, // 14: teleport.notifications.v1.NotificationService.ListUserNotificationStates:input_type -> teleport.notifications.v1.ListUserNotificationStatesRequest
- 11, // 15: teleport.notifications.v1.NotificationService.GetUserLastSeenNotification:input_type -> teleport.notifications.v1.GetUserLastSeenNotificationRequest
- 12, // 16: teleport.notifications.v1.NotificationService.UpsertUserLastSeenNotification:input_type -> teleport.notifications.v1.UpsertUserLastSeenNotificationRequest
- 13, // 17: teleport.notifications.v1.NotificationService.DeleteUserLastSeenNotification:input_type -> teleport.notifications.v1.DeleteUserLastSeenNotificationRequest
- 14, // 18: teleport.notifications.v1.NotificationService.CreateUserNotification:output_type -> teleport.notifications.v1.Notification
- 18, // 19: teleport.notifications.v1.NotificationService.DeleteUserNotification:output_type -> google.protobuf.Empty
- 15, // 20: teleport.notifications.v1.NotificationService.CreateGlobalNotification:output_type -> teleport.notifications.v1.GlobalNotification
- 18, // 21: teleport.notifications.v1.NotificationService.DeleteGlobalNotification:output_type -> google.protobuf.Empty
- 3, // 22: teleport.notifications.v1.NotificationService.ListUserNotifications:output_type -> teleport.notifications.v1.ListUserNotificationsResponse
- 16, // 23: teleport.notifications.v1.NotificationService.UpsertUserNotificationState:output_type -> teleport.notifications.v1.UserNotificationState
- 18, // 24: teleport.notifications.v1.NotificationService.DeleteUserNotificationState:output_type -> google.protobuf.Empty
- 10, // 25: teleport.notifications.v1.NotificationService.ListUserNotificationStates:output_type -> teleport.notifications.v1.ListUserNotificationStatesResponse
- 17, // 26: teleport.notifications.v1.NotificationService.GetUserLastSeenNotification:output_type -> teleport.notifications.v1.UserLastSeenNotification
- 17, // 27: teleport.notifications.v1.NotificationService.UpsertUserLastSeenNotification:output_type -> teleport.notifications.v1.UserLastSeenNotification
- 18, // 28: teleport.notifications.v1.NotificationService.DeleteUserLastSeenNotification:output_type -> google.protobuf.Empty
- 18, // [18:29] is the sub-list for method output_type
- 7, // [7:18] is the sub-list for method input_type
- 7, // [7:7] is the sub-list for extension type_name
- 7, // [7:7] is the sub-list for extension extendee
- 0, // [0:7] is the sub-list for field type_name
+ 8, // 0: teleport.notifications.v1.CreateUserNotificationRequest.notification:type_name -> teleport.notifications.v1.Notification
+ 8, // 1: teleport.notifications.v1.ListNotificationsResponse.notifications:type_name -> teleport.notifications.v1.Notification
+ 9, // 2: teleport.notifications.v1.ListNotificationsResponse.user_last_seen_notification_timestamp:type_name -> google.protobuf.Timestamp
+ 10, // 3: teleport.notifications.v1.CreateGlobalNotificationRequest.global_notification:type_name -> teleport.notifications.v1.GlobalNotification
+ 11, // 4: teleport.notifications.v1.UpsertUserNotificationStateRequest.user_notification_state:type_name -> teleport.notifications.v1.UserNotificationState
+ 12, // 5: teleport.notifications.v1.UpsertUserLastSeenNotificationRequest.user_last_seen_notification:type_name -> teleport.notifications.v1.UserLastSeenNotification
+ 0, // 6: teleport.notifications.v1.NotificationService.CreateUserNotification:input_type -> teleport.notifications.v1.CreateUserNotificationRequest
+ 1, // 7: teleport.notifications.v1.NotificationService.DeleteUserNotification:input_type -> teleport.notifications.v1.DeleteUserNotificationRequest
+ 4, // 8: teleport.notifications.v1.NotificationService.CreateGlobalNotification:input_type -> teleport.notifications.v1.CreateGlobalNotificationRequest
+ 5, // 9: teleport.notifications.v1.NotificationService.DeleteGlobalNotification:input_type -> teleport.notifications.v1.DeleteGlobalNotificationRequest
+ 2, // 10: teleport.notifications.v1.NotificationService.ListNotifications:input_type -> teleport.notifications.v1.ListNotificationsRequest
+ 6, // 11: teleport.notifications.v1.NotificationService.UpsertUserNotificationState:input_type -> teleport.notifications.v1.UpsertUserNotificationStateRequest
+ 7, // 12: teleport.notifications.v1.NotificationService.UpsertUserLastSeenNotification:input_type -> teleport.notifications.v1.UpsertUserLastSeenNotificationRequest
+ 8, // 13: teleport.notifications.v1.NotificationService.CreateUserNotification:output_type -> teleport.notifications.v1.Notification
+ 13, // 14: teleport.notifications.v1.NotificationService.DeleteUserNotification:output_type -> google.protobuf.Empty
+ 10, // 15: teleport.notifications.v1.NotificationService.CreateGlobalNotification:output_type -> teleport.notifications.v1.GlobalNotification
+ 13, // 16: teleport.notifications.v1.NotificationService.DeleteGlobalNotification:output_type -> google.protobuf.Empty
+ 3, // 17: teleport.notifications.v1.NotificationService.ListNotifications:output_type -> teleport.notifications.v1.ListNotificationsResponse
+ 11, // 18: teleport.notifications.v1.NotificationService.UpsertUserNotificationState:output_type -> teleport.notifications.v1.UserNotificationState
+ 12, // 19: teleport.notifications.v1.NotificationService.UpsertUserLastSeenNotification:output_type -> teleport.notifications.v1.UserLastSeenNotification
+ 13, // [13:20] is the sub-list for method output_type
+ 6, // [6:13] is the sub-list for method input_type
+ 6, // [6:6] is the sub-list for extension type_name
+ 6, // [6:6] is the sub-list for extension extendee
+ 0, // [0:6] is the sub-list for field type_name
}
func init() { file_teleport_notifications_v1_notifications_service_proto_init() }
@@ -1141,7 +737,7 @@ func file_teleport_notifications_v1_notifications_service_proto_init() {
}
}
file_teleport_notifications_v1_notifications_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*ListUserNotificationsRequest); i {
+ switch v := v.(*ListNotificationsRequest); i {
case 0:
return &v.state
case 1:
@@ -1153,7 +749,7 @@ func file_teleport_notifications_v1_notifications_service_proto_init() {
}
}
file_teleport_notifications_v1_notifications_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*ListUserNotificationsResponse); i {
+ switch v := v.(*ListNotificationsResponse); i {
case 0:
return &v.state
case 1:
@@ -1201,66 +797,6 @@ func file_teleport_notifications_v1_notifications_service_proto_init() {
}
}
file_teleport_notifications_v1_notifications_service_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*UpdateUserNotificationStateRequest); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_teleport_notifications_v1_notifications_service_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*DeleteUserNotificationStateRequest); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_teleport_notifications_v1_notifications_service_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*ListUserNotificationStatesRequest); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_teleport_notifications_v1_notifications_service_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*ListUserNotificationStatesResponse); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_teleport_notifications_v1_notifications_service_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*GetUserLastSeenNotificationRequest); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- file_teleport_notifications_v1_notifications_service_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*UpsertUserLastSeenNotificationRequest); i {
case 0:
return &v.state
@@ -1272,18 +808,6 @@ func file_teleport_notifications_v1_notifications_service_proto_init() {
return nil
}
}
- file_teleport_notifications_v1_notifications_service_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*DeleteUserLastSeenNotificationRequest); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
}
type x struct{}
out := protoimpl.TypeBuilder{
@@ -1291,7 +815,7 @@ func file_teleport_notifications_v1_notifications_service_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_teleport_notifications_v1_notifications_service_proto_rawDesc,
NumEnums: 0,
- NumMessages: 14,
+ NumMessages: 8,
NumExtensions: 0,
NumServices: 1,
},
diff --git a/api/gen/proto/go/teleport/notifications/v1/notifications_service_grpc.pb.go b/api/gen/proto/go/teleport/notifications/v1/notifications_service_grpc.pb.go
index 4c84d1a6a27..a00e1de288d 100644
--- a/api/gen/proto/go/teleport/notifications/v1/notifications_service_grpc.pb.go
+++ b/api/gen/proto/go/teleport/notifications/v1/notifications_service_grpc.pb.go
@@ -41,13 +41,9 @@ const (
NotificationService_DeleteUserNotification_FullMethodName = "/teleport.notifications.v1.NotificationService/DeleteUserNotification"
NotificationService_CreateGlobalNotification_FullMethodName = "/teleport.notifications.v1.NotificationService/CreateGlobalNotification"
NotificationService_DeleteGlobalNotification_FullMethodName = "/teleport.notifications.v1.NotificationService/DeleteGlobalNotification"
- NotificationService_ListUserNotifications_FullMethodName = "/teleport.notifications.v1.NotificationService/ListUserNotifications"
+ NotificationService_ListNotifications_FullMethodName = "/teleport.notifications.v1.NotificationService/ListNotifications"
NotificationService_UpsertUserNotificationState_FullMethodName = "/teleport.notifications.v1.NotificationService/UpsertUserNotificationState"
- NotificationService_DeleteUserNotificationState_FullMethodName = "/teleport.notifications.v1.NotificationService/DeleteUserNotificationState"
- NotificationService_ListUserNotificationStates_FullMethodName = "/teleport.notifications.v1.NotificationService/ListUserNotificationStates"
- NotificationService_GetUserLastSeenNotification_FullMethodName = "/teleport.notifications.v1.NotificationService/GetUserLastSeenNotification"
NotificationService_UpsertUserLastSeenNotification_FullMethodName = "/teleport.notifications.v1.NotificationService/UpsertUserLastSeenNotification"
- NotificationService_DeleteUserLastSeenNotification_FullMethodName = "/teleport.notifications.v1.NotificationService/DeleteUserLastSeenNotification"
)
// NotificationServiceClient is the client API for NotificationService service.
@@ -62,20 +58,12 @@ type NotificationServiceClient interface {
CreateGlobalNotification(ctx context.Context, in *CreateGlobalNotificationRequest, opts ...grpc.CallOption) (*GlobalNotification, error)
// DeleteGlobalNotification deletes a global notification.
DeleteGlobalNotification(ctx context.Context, in *DeleteGlobalNotificationRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
- // ListUserNotificationsRequest is the request for listing a user's notifications, which include user-specific ones as well as global notifications that match them.
- ListUserNotifications(ctx context.Context, in *ListUserNotificationsRequest, opts ...grpc.CallOption) (*ListUserNotificationsResponse, error)
+ // ListNotifications returns a paginated list of a user's notifications.
+ ListNotifications(ctx context.Context, in *ListNotificationsRequest, opts ...grpc.CallOption) (*ListNotificationsResponse, error)
// UpsertUserNotificationState creates or updates a user notification state which records whether the user has clicked on or dismissed a notification.
UpsertUserNotificationState(ctx context.Context, in *UpsertUserNotificationStateRequest, opts ...grpc.CallOption) (*UserNotificationState, error)
- // DeleteUserNotificationState deletes a user notification state object.
- DeleteUserNotificationState(ctx context.Context, in *DeleteUserNotificationStateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
- // ListUserNotificationStates returns a page of a user's notification states.
- ListUserNotificationStates(ctx context.Context, in *ListUserNotificationStatesRequest, opts ...grpc.CallOption) (*ListUserNotificationStatesResponse, error)
- // GetUserLastSeenNotification returns a user's last seen notification item.
- GetUserLastSeenNotification(ctx context.Context, in *GetUserLastSeenNotificationRequest, opts ...grpc.CallOption) (*UserLastSeenNotification, error)
// UpsertUserLastSeenNotification creates or updates a user's last seen notification item.
UpsertUserLastSeenNotification(ctx context.Context, in *UpsertUserLastSeenNotificationRequest, opts ...grpc.CallOption) (*UserLastSeenNotification, error)
- // DeleteUserLastSeenNotification deletes a user's last seen notification item.
- DeleteUserLastSeenNotification(ctx context.Context, in *DeleteUserLastSeenNotificationRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
}
type notificationServiceClient struct {
@@ -122,9 +110,9 @@ func (c *notificationServiceClient) DeleteGlobalNotification(ctx context.Context
return out, nil
}
-func (c *notificationServiceClient) ListUserNotifications(ctx context.Context, in *ListUserNotificationsRequest, opts ...grpc.CallOption) (*ListUserNotificationsResponse, error) {
- out := new(ListUserNotificationsResponse)
- err := c.cc.Invoke(ctx, NotificationService_ListUserNotifications_FullMethodName, in, out, opts...)
+func (c *notificationServiceClient) ListNotifications(ctx context.Context, in *ListNotificationsRequest, opts ...grpc.CallOption) (*ListNotificationsResponse, error) {
+ out := new(ListNotificationsResponse)
+ err := c.cc.Invoke(ctx, NotificationService_ListNotifications_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
@@ -140,33 +128,6 @@ func (c *notificationServiceClient) UpsertUserNotificationState(ctx context.Cont
return out, nil
}
-func (c *notificationServiceClient) DeleteUserNotificationState(ctx context.Context, in *DeleteUserNotificationStateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
- out := new(emptypb.Empty)
- err := c.cc.Invoke(ctx, NotificationService_DeleteUserNotificationState_FullMethodName, in, out, opts...)
- if err != nil {
- return nil, err
- }
- return out, nil
-}
-
-func (c *notificationServiceClient) ListUserNotificationStates(ctx context.Context, in *ListUserNotificationStatesRequest, opts ...grpc.CallOption) (*ListUserNotificationStatesResponse, error) {
- out := new(ListUserNotificationStatesResponse)
- err := c.cc.Invoke(ctx, NotificationService_ListUserNotificationStates_FullMethodName, in, out, opts...)
- if err != nil {
- return nil, err
- }
- return out, nil
-}
-
-func (c *notificationServiceClient) GetUserLastSeenNotification(ctx context.Context, in *GetUserLastSeenNotificationRequest, opts ...grpc.CallOption) (*UserLastSeenNotification, error) {
- out := new(UserLastSeenNotification)
- err := c.cc.Invoke(ctx, NotificationService_GetUserLastSeenNotification_FullMethodName, in, out, opts...)
- if err != nil {
- return nil, err
- }
- return out, nil
-}
-
func (c *notificationServiceClient) UpsertUserLastSeenNotification(ctx context.Context, in *UpsertUserLastSeenNotificationRequest, opts ...grpc.CallOption) (*UserLastSeenNotification, error) {
out := new(UserLastSeenNotification)
err := c.cc.Invoke(ctx, NotificationService_UpsertUserLastSeenNotification_FullMethodName, in, out, opts...)
@@ -176,15 +137,6 @@ func (c *notificationServiceClient) UpsertUserLastSeenNotification(ctx context.C
return out, nil
}
-func (c *notificationServiceClient) DeleteUserLastSeenNotification(ctx context.Context, in *DeleteUserLastSeenNotificationRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
- out := new(emptypb.Empty)
- err := c.cc.Invoke(ctx, NotificationService_DeleteUserLastSeenNotification_FullMethodName, in, out, opts...)
- if err != nil {
- return nil, err
- }
- return out, nil
-}
-
// NotificationServiceServer is the server API for NotificationService service.
// All implementations must embed UnimplementedNotificationServiceServer
// for forward compatibility
@@ -197,20 +149,12 @@ type NotificationServiceServer interface {
CreateGlobalNotification(context.Context, *CreateGlobalNotificationRequest) (*GlobalNotification, error)
// DeleteGlobalNotification deletes a global notification.
DeleteGlobalNotification(context.Context, *DeleteGlobalNotificationRequest) (*emptypb.Empty, error)
- // ListUserNotificationsRequest is the request for listing a user's notifications, which include user-specific ones as well as global notifications that match them.
- ListUserNotifications(context.Context, *ListUserNotificationsRequest) (*ListUserNotificationsResponse, error)
+ // ListNotifications returns a paginated list of a user's notifications.
+ ListNotifications(context.Context, *ListNotificationsRequest) (*ListNotificationsResponse, error)
// UpsertUserNotificationState creates or updates a user notification state which records whether the user has clicked on or dismissed a notification.
UpsertUserNotificationState(context.Context, *UpsertUserNotificationStateRequest) (*UserNotificationState, error)
- // DeleteUserNotificationState deletes a user notification state object.
- DeleteUserNotificationState(context.Context, *DeleteUserNotificationStateRequest) (*emptypb.Empty, error)
- // ListUserNotificationStates returns a page of a user's notification states.
- ListUserNotificationStates(context.Context, *ListUserNotificationStatesRequest) (*ListUserNotificationStatesResponse, error)
- // GetUserLastSeenNotification returns a user's last seen notification item.
- GetUserLastSeenNotification(context.Context, *GetUserLastSeenNotificationRequest) (*UserLastSeenNotification, error)
// UpsertUserLastSeenNotification creates or updates a user's last seen notification item.
UpsertUserLastSeenNotification(context.Context, *UpsertUserLastSeenNotificationRequest) (*UserLastSeenNotification, error)
- // DeleteUserLastSeenNotification deletes a user's last seen notification item.
- DeleteUserLastSeenNotification(context.Context, *DeleteUserLastSeenNotificationRequest) (*emptypb.Empty, error)
mustEmbedUnimplementedNotificationServiceServer()
}
@@ -230,27 +174,15 @@ func (UnimplementedNotificationServiceServer) CreateGlobalNotification(context.C
func (UnimplementedNotificationServiceServer) DeleteGlobalNotification(context.Context, *DeleteGlobalNotificationRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteGlobalNotification not implemented")
}
-func (UnimplementedNotificationServiceServer) ListUserNotifications(context.Context, *ListUserNotificationsRequest) (*ListUserNotificationsResponse, error) {
- return nil, status.Errorf(codes.Unimplemented, "method ListUserNotifications not implemented")
+func (UnimplementedNotificationServiceServer) ListNotifications(context.Context, *ListNotificationsRequest) (*ListNotificationsResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method ListNotifications not implemented")
}
func (UnimplementedNotificationServiceServer) UpsertUserNotificationState(context.Context, *UpsertUserNotificationStateRequest) (*UserNotificationState, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpsertUserNotificationState not implemented")
}
-func (UnimplementedNotificationServiceServer) DeleteUserNotificationState(context.Context, *DeleteUserNotificationStateRequest) (*emptypb.Empty, error) {
- return nil, status.Errorf(codes.Unimplemented, "method DeleteUserNotificationState not implemented")
-}
-func (UnimplementedNotificationServiceServer) ListUserNotificationStates(context.Context, *ListUserNotificationStatesRequest) (*ListUserNotificationStatesResponse, error) {
- return nil, status.Errorf(codes.Unimplemented, "method ListUserNotificationStates not implemented")
-}
-func (UnimplementedNotificationServiceServer) GetUserLastSeenNotification(context.Context, *GetUserLastSeenNotificationRequest) (*UserLastSeenNotification, error) {
- return nil, status.Errorf(codes.Unimplemented, "method GetUserLastSeenNotification not implemented")
-}
func (UnimplementedNotificationServiceServer) UpsertUserLastSeenNotification(context.Context, *UpsertUserLastSeenNotificationRequest) (*UserLastSeenNotification, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpsertUserLastSeenNotification not implemented")
}
-func (UnimplementedNotificationServiceServer) DeleteUserLastSeenNotification(context.Context, *DeleteUserLastSeenNotificationRequest) (*emptypb.Empty, error) {
- return nil, status.Errorf(codes.Unimplemented, "method DeleteUserLastSeenNotification not implemented")
-}
func (UnimplementedNotificationServiceServer) mustEmbedUnimplementedNotificationServiceServer() {}
// UnsafeNotificationServiceServer may be embedded to opt out of forward compatibility for this service.
@@ -336,20 +268,20 @@ func _NotificationService_DeleteGlobalNotification_Handler(srv interface{}, ctx
return interceptor(ctx, in, info, handler)
}
-func _NotificationService_ListUserNotifications_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(ListUserNotificationsRequest)
+func _NotificationService_ListNotifications_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ListNotificationsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
- return srv.(NotificationServiceServer).ListUserNotifications(ctx, in)
+ return srv.(NotificationServiceServer).ListNotifications(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
- FullMethod: NotificationService_ListUserNotifications_FullMethodName,
+ FullMethod: NotificationService_ListNotifications_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(NotificationServiceServer).ListUserNotifications(ctx, req.(*ListUserNotificationsRequest))
+ return srv.(NotificationServiceServer).ListNotifications(ctx, req.(*ListNotificationsRequest))
}
return interceptor(ctx, in, info, handler)
}
@@ -372,60 +304,6 @@ func _NotificationService_UpsertUserNotificationState_Handler(srv interface{}, c
return interceptor(ctx, in, info, handler)
}
-func _NotificationService_DeleteUserNotificationState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(DeleteUserNotificationStateRequest)
- if err := dec(in); err != nil {
- return nil, err
- }
- if interceptor == nil {
- return srv.(NotificationServiceServer).DeleteUserNotificationState(ctx, in)
- }
- info := &grpc.UnaryServerInfo{
- Server: srv,
- FullMethod: NotificationService_DeleteUserNotificationState_FullMethodName,
- }
- handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(NotificationServiceServer).DeleteUserNotificationState(ctx, req.(*DeleteUserNotificationStateRequest))
- }
- return interceptor(ctx, in, info, handler)
-}
-
-func _NotificationService_ListUserNotificationStates_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(ListUserNotificationStatesRequest)
- if err := dec(in); err != nil {
- return nil, err
- }
- if interceptor == nil {
- return srv.(NotificationServiceServer).ListUserNotificationStates(ctx, in)
- }
- info := &grpc.UnaryServerInfo{
- Server: srv,
- FullMethod: NotificationService_ListUserNotificationStates_FullMethodName,
- }
- handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(NotificationServiceServer).ListUserNotificationStates(ctx, req.(*ListUserNotificationStatesRequest))
- }
- return interceptor(ctx, in, info, handler)
-}
-
-func _NotificationService_GetUserLastSeenNotification_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(GetUserLastSeenNotificationRequest)
- if err := dec(in); err != nil {
- return nil, err
- }
- if interceptor == nil {
- return srv.(NotificationServiceServer).GetUserLastSeenNotification(ctx, in)
- }
- info := &grpc.UnaryServerInfo{
- Server: srv,
- FullMethod: NotificationService_GetUserLastSeenNotification_FullMethodName,
- }
- handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(NotificationServiceServer).GetUserLastSeenNotification(ctx, req.(*GetUserLastSeenNotificationRequest))
- }
- return interceptor(ctx, in, info, handler)
-}
-
func _NotificationService_UpsertUserLastSeenNotification_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpsertUserLastSeenNotificationRequest)
if err := dec(in); err != nil {
@@ -444,24 +322,6 @@ func _NotificationService_UpsertUserLastSeenNotification_Handler(srv interface{}
return interceptor(ctx, in, info, handler)
}
-func _NotificationService_DeleteUserLastSeenNotification_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
- in := new(DeleteUserLastSeenNotificationRequest)
- if err := dec(in); err != nil {
- return nil, err
- }
- if interceptor == nil {
- return srv.(NotificationServiceServer).DeleteUserLastSeenNotification(ctx, in)
- }
- info := &grpc.UnaryServerInfo{
- Server: srv,
- FullMethod: NotificationService_DeleteUserLastSeenNotification_FullMethodName,
- }
- handler := func(ctx context.Context, req interface{}) (interface{}, error) {
- return srv.(NotificationServiceServer).DeleteUserLastSeenNotification(ctx, req.(*DeleteUserLastSeenNotificationRequest))
- }
- return interceptor(ctx, in, info, handler)
-}
-
// NotificationService_ServiceDesc is the grpc.ServiceDesc for NotificationService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@@ -486,33 +346,17 @@ var NotificationService_ServiceDesc = grpc.ServiceDesc{
Handler: _NotificationService_DeleteGlobalNotification_Handler,
},
{
- MethodName: "ListUserNotifications",
- Handler: _NotificationService_ListUserNotifications_Handler,
+ MethodName: "ListNotifications",
+ Handler: _NotificationService_ListNotifications_Handler,
},
{
MethodName: "UpsertUserNotificationState",
Handler: _NotificationService_UpsertUserNotificationState_Handler,
},
- {
- MethodName: "DeleteUserNotificationState",
- Handler: _NotificationService_DeleteUserNotificationState_Handler,
- },
- {
- MethodName: "ListUserNotificationStates",
- Handler: _NotificationService_ListUserNotificationStates_Handler,
- },
- {
- MethodName: "GetUserLastSeenNotification",
- Handler: _NotificationService_GetUserLastSeenNotification_Handler,
- },
{
MethodName: "UpsertUserLastSeenNotification",
Handler: _NotificationService_UpsertUserLastSeenNotification_Handler,
},
- {
- MethodName: "DeleteUserLastSeenNotification",
- Handler: _NotificationService_DeleteUserLastSeenNotification_Handler,
- },
},
Streams: []grpc.StreamDesc{},
Metadata: "teleport/notifications/v1/notifications_service.proto",
diff --git a/api/proto/teleport/notifications/v1/notifications.proto b/api/proto/teleport/notifications/v1/notifications.proto
index 13b4c82e7d8..65bb366b34f 100644
--- a/api/proto/teleport/notifications/v1/notifications.proto
+++ b/api/proto/teleport/notifications/v1/notifications.proto
@@ -42,8 +42,8 @@ message Notification {
// NotificationSpec is the notification specification.
message NotificationSpec {
- // id is the UUID of the notification, in UUIDv7 format.
- string id = 1;
+ reserved 1;
+ reserved "id";
// created is when the notification was created, in UNIX time.
google.protobuf.Timestamp created = 2;
// unscoped is whether the notification shouldn't be restricted to a specific audience. This is to prevent the potential future possibility that a user-specific notification contains information that the user should no longer be allowed to see. Default is true.
diff --git a/api/proto/teleport/notifications/v1/notifications_service.proto b/api/proto/teleport/notifications/v1/notifications_service.proto
index 3d9ce708d83..ce3f53579c3 100644
--- a/api/proto/teleport/notifications/v1/notifications_service.proto
+++ b/api/proto/teleport/notifications/v1/notifications_service.proto
@@ -21,6 +21,7 @@ syntax = "proto3";
package teleport.notifications.v1;
import "google/protobuf/empty.proto";
+import "google/protobuf/timestamp.proto";
import "teleport/notifications/v1/notifications.proto";
option go_package = "github.com/gravitational/teleport/api/gen/proto/go/teleport/notifications/v1;notificationsv1";
@@ -37,22 +38,14 @@ service NotificationService {
// DeleteGlobalNotification deletes a global notification.
rpc DeleteGlobalNotification(DeleteGlobalNotificationRequest) returns (google.protobuf.Empty);
- // ListUserNotificationsRequest is the request for listing a user's notifications, which include user-specific ones as well as global notifications that match them.
- rpc ListUserNotifications(ListUserNotificationsRequest) returns (ListUserNotificationsResponse);
+ // ListNotifications returns a paginated list of a user's notifications.
+ rpc ListNotifications(ListNotificationsRequest) returns (ListNotificationsResponse);
// UpsertUserNotificationState creates or updates a user notification state which records whether the user has clicked on or dismissed a notification.
rpc UpsertUserNotificationState(UpsertUserNotificationStateRequest) returns (UserNotificationState);
- // DeleteUserNotificationState deletes a user notification state object.
- rpc DeleteUserNotificationState(DeleteUserNotificationStateRequest) returns (google.protobuf.Empty);
- // ListUserNotificationStates returns a page of a user's notification states.
- rpc ListUserNotificationStates(ListUserNotificationStatesRequest) returns (ListUserNotificationStatesResponse);
- // GetUserLastSeenNotification returns a user's last seen notification item.
- rpc GetUserLastSeenNotification(GetUserLastSeenNotificationRequest) returns (UserLastSeenNotification);
// UpsertUserLastSeenNotification creates or updates a user's last seen notification item.
rpc UpsertUserLastSeenNotification(UpsertUserLastSeenNotificationRequest) returns (UserLastSeenNotification);
- // DeleteUserLastSeenNotification deletes a user's last seen notification item.
- rpc DeleteUserLastSeenNotification(DeleteUserLastSeenNotificationRequest) returns (google.protobuf.Empty);
}
// CreateUserNotificationRequest is the request for creating a user-specific notification.
@@ -71,22 +64,22 @@ message DeleteUserNotificationRequest {
string notification_id = 2;
}
-// ListUserNotificationsRequest is the request for listing a user's notifications, which include user-specific ones as well as global notifications that match them.
-message ListUserNotificationsRequest {
- // username is the username of the user the notifications to list are for.
- string username = 1;
+// ListNotificationsRequest is the request for listing a user's notifications.
+message ListNotificationsRequest {
// page_size is the size of the page to return.
- int32 page_size = 2;
+ int32 page_size = 1;
// page_token is the next_page_token value returned from a previous ListUserNotifications request, if any.
- string page_token = 3;
+ string page_token = 2;
}
-// ListUserNotificationsResponse is the response from listing a user's user-specific notifications.
-message ListUserNotificationsResponse {
+// ListNotificationsResponse is the response from listing a user's notifications.
+message ListNotificationsResponse {
// notifications is the notifications returned.
repeated Notification notifications = 1;
- // next_page_token is the token to retrieve the next page of results, this will be empty if there are no more results.
- string next_page_token = 2;
+ // next_page_token contains the next page token to use as the start key for the next page of notifications.
+ string next_page_token = 3;
+ // user_last_seen_notification_timestamp is the timestamp of the last notification the user has seen.
+ google.protobuf.Timestamp user_last_seen_notification_timestamp = 4;
}
// CreateGlobalNotificationRequest is the request for creating a global notification.
@@ -109,52 +102,10 @@ message UpsertUserNotificationStateRequest {
UserNotificationState user_notification_state = 2;
}
-// UpdateUserNotificationStateRequest is the request for updating a user notification state.
-message UpdateUserNotificationStateRequest {
- // username is the username of the user.
- string username = 1;
- // user_notification_state is the updated user notification state.
- UserNotificationState user_notification_state = 2;
-}
-
-// DeleteUserNotificationState is the request for deleting a user notification state.
-message DeleteUserNotificationStateRequest {
- // username is the username of the user.
- string username = 1;
- // notification_id is the ID of the notification the notifiation state to delete is for.
- string notification_id = 2;
-}
-
-// ListUserNotificationStatesRequest is the request for listing a user's notification states.
-message ListUserNotificationStatesRequest {
- // username is the username of the user.
- string username = 1;
-}
-
-// ListUserNotificationStatesResponse is the response from listing a user's notification states.
-message ListUserNotificationStatesResponse {
- // notification_states is the user notification state items returned.
- repeated UserNotificationState notification_states = 1;
- // next_page_token is the token to retrieve the next page of results, this will be empty if there are no more results.
- string next_page_token = 2;
-}
-
-// GetUserLastSeenNotificationRequest is the request for getting a user's last seen notification.
-message GetUserLastSeenNotificationRequest {
- // username is the username of the user.
- string username = 1;
-}
-
// UpsertUserLastSeenNotificationRequest is the request for creating or updating a user's last seen notification.
message UpsertUserLastSeenNotificationRequest {
// username is the username of the user.
string username = 1;
- // user_notification_state is the udpated user last seen notification item.
+ // user_notification_state is the updated user last seen notification item.
UserLastSeenNotification user_last_seen_notification = 2;
}
-
-// DeleteUserLastSeenNotificationRequest is the request for deleting a user's last seen notification.
-message DeleteUserLastSeenNotificationRequest {
- // username is the username of the user.
- string username = 1;
-}
diff --git a/api/types/constants.go b/api/types/constants.go
index 2ce0c522252..ac4912ef805 100644
--- a/api/types/constants.go
+++ b/api/types/constants.go
@@ -986,6 +986,15 @@ const (
PluginGenerationLabel = TeleportInternalLabelPrefix + "plugin-generation"
)
+const (
+ // NotificationTitleLabel is the label which contains the title of the notification.
+ NotificationTitleLabel = TeleportInternalLabelPrefix + "title"
+ // NotificationClickedLabel is the label which contains whether the notification has been clicked on by the user.
+ NotificationClickedLabel = TeleportInternalLabelPrefix + "clicked"
+ // NotificationScope is the label which contains the scope of the notification, either "user" or "global"
+ NotificationScope = TeleportInternalLabelPrefix + "scope"
+)
+
const (
// InstallMethodAWSOIDCDeployServiceEnvVar is the env var used to detect if the agent was installed
// using the DeployService action of the AWS OIDC integration.
diff --git a/lib/auth/authclient/clt.go b/lib/auth/authclient/clt.go
index 43faf8ef6b6..e9840a71046 100644
--- a/lib/auth/authclient/clt.go
+++ b/lib/auth/authclient/clt.go
@@ -629,6 +629,10 @@ func (c *Client) IntegrationAWSOIDCClient() integrationv1.AWSOIDCServiceClient {
return integrationv1.NewAWSOIDCServiceClient(c.APIClient.GetConnection())
}
+func (c *Client) NotificationServiceClient() notificationsv1.NotificationServiceClient {
+ return notificationsv1.NewNotificationServiceClient(c.APIClient.GetConnection())
+}
+
// DiscoveryConfigClient returns a client for managing the DiscoveryConfig resource.
func (c *Client) DiscoveryConfigClient() services.DiscoveryConfigWithStatusUpdater {
return c.APIClient.DiscoveryConfigClient()
@@ -654,6 +658,22 @@ func (c *Client) SetStaticTokens(st types.StaticTokens) error {
return trace.NotImplemented(notImplementedMessage)
}
+// UpsertUserNotificationState creates or updates a user notification state which records whether the user has clicked on or dismissed a notification.
+func (c *Client) UpsertUserNotificationState(ctx context.Context, username string, uns *notificationsv1.UserNotificationState) (*notificationsv1.UserNotificationState, error) {
+ return c.APIClient.UpsertUserNotificationState(ctx, ¬ificationsv1.UpsertUserNotificationStateRequest{
+ Username: username,
+ UserNotificationState: uns,
+ })
+}
+
+// UpsertUserLastSeenNotification creates or updates a user's last seen notification item.
+func (c *Client) UpsertUserLastSeenNotification(ctx context.Context, username string, ulsn *notificationsv1.UserLastSeenNotification) (*notificationsv1.UserLastSeenNotification, error) {
+ return c.APIClient.UpsertUserLastSeenNotification(ctx, ¬ificationsv1.UpsertUserLastSeenNotificationRequest{
+ Username: username,
+ UserLastSeenNotification: ulsn,
+ })
+}
+
// CreateGlobalNotification creates a global notification.
func (c *Client) CreateGlobalNotification(ctx context.Context, globalNotification *notificationsv1.GlobalNotification) (*notificationsv1.GlobalNotification, error) {
// TODO(rudream): implement client methods for notifications
@@ -672,18 +692,6 @@ func (c *Client) DeleteGlobalNotification(ctx context.Context, notificationId st
return trace.NotImplemented(notImplementedMessage)
}
-// UpsertUserNotificationState creates or updates a user notification state which records whether the user has clicked on or dismissed a notification.
-func (c *Client) UpsertUserNotificationState(ctx context.Context, username string, state *notificationsv1.UserNotificationState) (*notificationsv1.UserNotificationState, error) {
- // TODO(rudream): implement client methods for notifications
- return nil, trace.NotImplemented(notImplementedMessage)
-}
-
-// UpsertUserLastSeenNotification creates or updates a user's last seen notification item.
-func (c *Client) UpsertUserLastSeenNotification(ctx context.Context, username string, ulsn *notificationsv1.UserLastSeenNotification) (*notificationsv1.UserLastSeenNotification, error) {
- // TODO(rudream): implement client methods for notifications
- return nil, trace.NotImplemented(notImplementedMessage)
-}
-
// DeleteAllGlobalNotifications not implemented: can only be called locally.
func (c *Client) DeleteAllGlobalNotifications(ctx context.Context) error {
return trace.NotImplemented(notImplementedMessage)
@@ -1608,6 +1616,12 @@ type ClientI interface {
// (as per the default gRPC behavior).
WorkloadIdentityServiceClient() machineidv1pb.WorkloadIdentityServiceClient
+ // NotificationServiceClient returns a notification service client.
+ // Clients connecting to older Teleport versions, still get a client
+ // when calling this method, but all RPCs will return "not implemented" errors
+ // (as per the default gRPC behavior).
+ NotificationServiceClient() notificationsv1.NotificationServiceClient
+
// ClusterConfigClient returns a Cluster Configuration client.
// Clients connecting to non-Enterprise clusters, or older Teleport versions,
// still get a client when calling this method, but all RPCs will return
diff --git a/lib/auth/grpcserver.go b/lib/auth/grpcserver.go
index 103800b7175..8cff469d22b 100644
--- a/lib/auth/grpcserver.go
+++ b/lib/auth/grpcserver.go
@@ -60,6 +60,7 @@ import (
loginrulepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/loginrule/v1"
machineidv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1"
mfav1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/mfa/v1"
+ notificationsv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/notifications/v1"
oktapb "github.com/gravitational/teleport/api/gen/proto/go/teleport/okta/v1"
presencev1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/presence/v1"
trustpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1"
@@ -83,6 +84,7 @@ import (
kubewaitingcontainerv1 "github.com/gravitational/teleport/lib/auth/kubewaitingcontainer"
"github.com/gravitational/teleport/lib/auth/loginrule"
"github.com/gravitational/teleport/lib/auth/machineid/machineidv1"
+ notifications "github.com/gravitational/teleport/lib/auth/notifications/notificationsv1"
"github.com/gravitational/teleport/lib/auth/okta"
"github.com/gravitational/teleport/lib/auth/presence/presencev1"
"github.com/gravitational/teleport/lib/auth/trust/trustv1"
@@ -5300,6 +5302,18 @@ func NewGRPCServer(cfg GRPCServerConfig) (*GRPCServer, error) {
}
accessmonitoringrules.RegisterAccessMonitoringRulesServiceServer(server, accessMonitoringRuleServer)
+ // Initialize and register the notifications service.
+ notificationsServer, err := notifications.NewService(notifications.ServiceConfig{
+ Authorizer: cfg.Authorizer,
+ Backend: cfg.AuthServer.Services,
+ UserNotificationCache: cfg.AuthServer.UserNotificationCache,
+ GlobalNotificationCache: cfg.AuthServer.GlobalNotificationCache,
+ })
+ if err != nil {
+ return nil, trace.Wrap(err)
+ }
+ notificationsv1.RegisterNotificationServiceServer(server, notificationsServer)
+
// Only register the service if this is an open source build. Enterprise builds
// register the actual service via an auth plugin, if we register here then all
// Enterprise builds would fail with a duplicate service registered error.
diff --git a/lib/auth/helpers.go b/lib/auth/helpers.go
index 712c8248c52..c262cb03264 100644
--- a/lib/auth/helpers.go
+++ b/lib/auth/helpers.go
@@ -298,6 +298,7 @@ func NewTestAuthServer(cfg TestAuthServerConfig) (*TestAuthServer, error) {
SkipPeriodicOperations: true,
Emitter: emitter,
TraceClient: cfg.TraceClient,
+ Clock: cfg.Clock,
KeyStoreConfig: keystore.Config{
Software: keystore.SoftwareConfig{
RSAKeyPairSource: authority.New().GenerateKeyPair,
diff --git a/lib/auth/notification_test.go b/lib/auth/notification_test.go
new file mode 100644
index 00000000000..3a2feec7e8b
--- /dev/null
+++ b/lib/auth/notification_test.go
@@ -0,0 +1,445 @@
+/*
+ * Teleport
+ * Copyright (C) 2024 Gravitational, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package auth
+
+import (
+ "context"
+ "fmt"
+ "testing"
+ "time"
+
+ "github.com/gravitational/trace"
+ "github.com/jonboulle/clockwork"
+ "github.com/stretchr/testify/require"
+ "google.golang.org/protobuf/types/known/timestamppb"
+
+ headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1"
+ notificationsv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/notifications/v1"
+ "github.com/gravitational/teleport/api/types"
+ "github.com/gravitational/teleport/lib/services"
+)
+
+func TestNotifications(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ t.Cleanup(cancel)
+
+ fakeClock := clockwork.NewFakeClock()
+
+ authServer, err := NewTestAuthServer(TestAuthServerConfig{
+ Dir: t.TempDir(),
+ Clock: fakeClock,
+ CacheEnabled: true,
+ })
+ require.NoError(t, err)
+
+ srv, err := authServer.NewTestTLSServer()
+
+ require.NoError(t, err)
+ t.Cleanup(func() { require.NoError(t, srv.Close()) })
+
+ roles := map[string]types.RoleSpecV6{
+ // auditors have access to nodes and databases, and the "auditor" and "user" logins
+ "auditors": {
+ Allow: types.RoleConditions{
+ Logins: []string{"auditor", "user"},
+ Rules: []types.Rule{
+ {
+ Resources: []string{types.KindNode, types.KindDatabase},
+ Verbs: services.RW(),
+ },
+ },
+ },
+ },
+ // managers have access to review requests for the "intern" role
+ "managers": {
+ Allow: types.RoleConditions{
+ Logins: []string{"user"},
+ ReviewRequests: &types.AccessReviewConditions{
+ Roles: []string{"intern"},
+ },
+ },
+ },
+ }
+ for roleName, roleSpec := range roles {
+ role, err := types.NewRole(roleName, roleSpec)
+ require.NoError(t, err)
+
+ _, err = srv.Auth().UpsertRole(ctx, role)
+ require.NoError(t, err)
+ }
+
+ auditorUsername := "auditor"
+ managerUsername := "manager"
+
+ userRolesMap := map[string][]string{
+ auditorUsername: {"auditors"},
+ managerUsername: {"managers"},
+ }
+
+ // Create the users with their roles.
+ for username, roles := range userRolesMap {
+ user, err := types.NewUser(username)
+ require.NoError(t, err)
+ user.SetRoles(roles)
+ _, err = srv.Auth().UpsertUser(ctx, user)
+ require.NoError(t, err)
+ }
+
+ // Describes a set of mock notifications to be created.
+ // The number in each notification's description represents the creation order of the notifications.
+ // eg. "auditor-3" will be the third notification created for auditor, and the third from last in the list (since it's the third oldest),
+ testNotifications := []struct {
+ userNotification *notificationsv1.Notification
+ globalNotification *notificationsv1.GlobalNotification
+ }{
+ {
+ userNotification: newUserNotification(t, auditorUsername, "auditor-1"),
+ },
+ {
+ userNotification: newUserNotification(t, auditorUsername, "auditor-2"),
+ },
+ {
+ // Matcher matches by the role "auditors"
+ globalNotification: newGlobalNotification(t, "auditor-3", ¬ificationsv1.GlobalNotificationSpec{
+ Matcher: ¬ificationsv1.GlobalNotificationSpec_ByRoles{
+ ByRoles: ¬ificationsv1.ByRoles{
+ Roles: []string{userRolesMap[auditorUsername][0]},
+ },
+ },
+ }),
+ },
+ {
+ // Matcher matches by the role "managers"
+ globalNotification: newGlobalNotification(t, "manager-1", ¬ificationsv1.GlobalNotificationSpec{
+ Matcher: ¬ificationsv1.GlobalNotificationSpec_ByRoles{
+ ByRoles: ¬ificationsv1.ByRoles{
+ Roles: []string{userRolesMap[managerUsername][0]},
+ },
+ },
+ }),
+ },
+ {
+ userNotification: newUserNotification(t, auditorUsername, "auditor-4"),
+ },
+ {
+ // Matcher matches all, both users should see this.
+ globalNotification: newGlobalNotification(t, "auditor-5,manager-2", ¬ificationsv1.GlobalNotificationSpec{
+ Matcher: ¬ificationsv1.GlobalNotificationSpec_All{
+ All: true,
+ },
+ }),
+ },
+ {
+ userNotification: newUserNotification(t, managerUsername, "manager-3"),
+ },
+ {
+ // Matcher matches by read & write permission on nodes.
+ globalNotification: newGlobalNotification(t, "auditor-6", ¬ificationsv1.GlobalNotificationSpec{
+ Matcher: ¬ificationsv1.GlobalNotificationSpec_ByPermissions{
+ ByPermissions: ¬ificationsv1.ByPermissions{
+ RoleConditions: []*types.RoleConditions{
+ {
+ Rules: []types.Rule{
+ {
+ Resources: []string{types.KindNode},
+ Verbs: services.RW(),
+ },
+ },
+ },
+ },
+ },
+ },
+ }),
+ },
+ {
+ // Matcher matches by the logins "auditor" and "user". Auditor has both of them, but manager only has "user", since we set MatchAllConditions to true, only auditor
+ // should get this notification.
+ globalNotification: newGlobalNotification(t, "auditor-7", ¬ificationsv1.GlobalNotificationSpec{
+ Matcher: ¬ificationsv1.GlobalNotificationSpec_ByPermissions{
+ ByPermissions: ¬ificationsv1.ByPermissions{
+ RoleConditions: []*types.RoleConditions{
+ {
+ Logins: []string{"auditor"},
+ },
+ {
+ Logins: []string{"user"},
+ },
+ },
+ },
+ },
+ MatchAllConditions: true,
+ }),
+ },
+ {
+ // Matcher matches by permission to review access requests for "intern"
+ globalNotification: newGlobalNotification(t, "manager-4", ¬ificationsv1.GlobalNotificationSpec{
+ Matcher: ¬ificationsv1.GlobalNotificationSpec_ByPermissions{
+ ByPermissions: ¬ificationsv1.ByPermissions{
+ RoleConditions: []*types.RoleConditions{
+ {
+ ReviewRequests: &types.AccessReviewConditions{
+ Roles: []string{"intern"},
+ },
+ },
+ },
+ },
+ },
+ }),
+ },
+ {
+ userNotification: newUserNotification(t, managerUsername, "manager-5"),
+ },
+ {
+ // Matcher matches by the logins "auditor" and "user". Both of them have "user" and MatchAllConditions is false, so both should get this notification.
+ globalNotification: newGlobalNotification(t, "auditor-8,manager-6", ¬ificationsv1.GlobalNotificationSpec{
+ Matcher: ¬ificationsv1.GlobalNotificationSpec_ByPermissions{
+ ByPermissions: ¬ificationsv1.ByPermissions{
+ RoleConditions: []*types.RoleConditions{
+ {
+ Logins: []string{"auditor"},
+ },
+ {
+ Logins: []string{"user"},
+ },
+ },
+ },
+ },
+ }),
+ },
+ }
+
+ notificationIdMap := map[string]string{}
+
+ // Create the notifications.
+ for _, n := range testNotifications {
+ // We add a small delay to ensure that the timestamps in the generated UUID's are all different and in the correct order.
+ // This is to prevent flakiness caused by the notifications being created in such quick succession that the timestamps are the same.
+ fakeClock.Advance(50 * time.Millisecond)
+ time.Sleep(50 * time.Millisecond)
+ // Create the notification in the backend.
+ if n.globalNotification != nil {
+ created, err := srv.Auth().CreateGlobalNotification(ctx, n.globalNotification)
+ notificationIdMap[created.GetSpec().GetNotification().GetMetadata().GetLabels()[types.NotificationTitleLabel]] = created.GetMetadata().GetName()
+ require.NoError(t, err)
+ continue
+ }
+ created, err := srv.Auth().CreateUserNotification(ctx, n.userNotification)
+ notificationIdMap[created.GetMetadata().GetLabels()[types.NotificationTitleLabel]] = created.GetMetadata().GetName()
+ require.NoError(t, err)
+ }
+
+ // Test fetching notifications for auditor.
+ auditorClient, err := srv.NewClient(TestUser(auditorUsername))
+ require.NoError(t, err)
+ defer auditorClient.Close()
+
+ auditorExpectedNotifications := []string{"auditor-8,manager-6", "auditor-7", "auditor-6", "auditor-5,manager-2", "auditor-4", "auditor-3", "auditor-2", "auditor-1"}
+
+ var finalOut []*notificationsv1.Notification
+
+ // Upsert auditor's last seen timestamp.
+ lastSeenTimestamp := timestamppb.New(time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC))
+ _, err = auditorClient.UpsertUserLastSeenNotification(ctx, auditorUsername, ¬ificationsv1.UserLastSeenNotification{
+ Status: ¬ificationsv1.UserLastSeenNotificationStatus{
+ LastSeenTime: lastSeenTimestamp,
+ },
+ })
+ require.NoError(t, err)
+
+ // Fetch a page of 3 notifications.
+ resp, err := auditorClient.ListNotifications(ctx, ¬ificationsv1.ListNotificationsRequest{
+ PageSize: 3,
+ })
+ require.NoError(t, err)
+ require.Equal(t, auditorExpectedNotifications[:3], notificationsToTitlesList(t, resp.Notifications))
+ finalOut = append(finalOut, resp.Notifications...)
+
+ // Verify that the nextKeys are correct.
+ expectedUserNotifsNextKey := notificationIdMap["auditor-4"]
+ expectedGlobalNotifsNextKey := notificationIdMap["auditor-5,manager-2"]
+ expectedNextKeys := fmt.Sprintf("%s,%s",
+ expectedUserNotifsNextKey,
+ expectedGlobalNotifsNextKey) // ","
+
+ require.Equal(t, expectedNextKeys, resp.NextPageToken)
+ require.Equal(t, lastSeenTimestamp.GetSeconds(), resp.UserLastSeenNotificationTimestamp.GetSeconds())
+
+ // Fetch the next 3 notifications, starting from the previously received startKeys.
+ // After this fetch, there should be no more global notifications for auditor, so the next page token
+ // for global notifications should be "end".
+ resp, err = auditorClient.ListNotifications(ctx, ¬ificationsv1.ListNotificationsRequest{
+ PageSize: 3,
+ PageToken: resp.NextPageToken,
+ })
+ require.NoError(t, err)
+ expectedNextKeys = fmt.Sprintf("%s,", notificationIdMap["auditor-2"])
+
+ require.Equal(t, expectedNextKeys, resp.NextPageToken)
+ finalOut = append(finalOut, resp.Notifications...)
+
+ // Fetch the rest of the notifications, starting from the previously received startKeys.
+ resp, err = auditorClient.ListNotifications(ctx, ¬ificationsv1.ListNotificationsRequest{
+ PageSize: 10,
+ PageToken: resp.NextPageToken,
+ })
+ require.NoError(t, err)
+ finalOut = append(finalOut, resp.Notifications...)
+ // Verify that all the notifications are in the list and in correct order.
+ require.Equal(t, auditorExpectedNotifications, notificationsToTitlesList(t, finalOut))
+ // Verify that we've reached the end of both lists.
+ require.Equal(t, "", resp.NextPageToken)
+
+ // Mark "auditor-2" and "auditor-5,manager-2" as dismissed.
+ _, err = auditorClient.UpsertUserNotificationState(ctx, auditorUsername, ¬ificationsv1.UserNotificationState{
+ Spec: ¬ificationsv1.UserNotificationStateSpec{
+ NotificationId: notificationIdMap["auditor-2"],
+ },
+ Status: ¬ificationsv1.UserNotificationStateStatus{
+ NotificationState: notificationsv1.NotificationState_NOTIFICATION_STATE_DISMISSED,
+ },
+ })
+ require.NoError(t, err)
+ _, err = auditorClient.UpsertUserNotificationState(ctx, auditorUsername, ¬ificationsv1.UserNotificationState{
+ Spec: ¬ificationsv1.UserNotificationStateSpec{
+ NotificationId: notificationIdMap["auditor-5,manager-2"],
+ },
+ Status: ¬ificationsv1.UserNotificationStateStatus{
+ NotificationState: notificationsv1.NotificationState_NOTIFICATION_STATE_DISMISSED,
+ },
+ })
+ require.NoError(t, err)
+
+ // Fetch notifications again and verify that the dismissed notifications are not returned.
+ resp, err = auditorClient.ListNotifications(ctx, ¬ificationsv1.ListNotificationsRequest{
+ PageSize: 10,
+ })
+ auditorExpectedNotifsAfterDismissal := []string{"auditor-8,manager-6", "auditor-7", "auditor-6", "auditor-4", "auditor-3", "auditor-1"}
+ require.NoError(t, err)
+ require.Equal(t, auditorExpectedNotifsAfterDismissal, notificationsToTitlesList(t, resp.Notifications))
+
+ // Test fetching notifications for manager.
+ managerClient, err := srv.NewClient(TestUser(managerUsername))
+ require.NoError(t, err)
+ defer managerClient.Close()
+
+ managerExpectedNotifications := []string{"auditor-8,manager-6", "manager-5", "manager-4", "manager-3", "auditor-5,manager-2", "manager-1"}
+
+ resp, err = managerClient.ListNotifications(ctx, ¬ificationsv1.ListNotificationsRequest{
+ PageSize: 10,
+ })
+ require.NoError(t, err)
+
+ require.Equal(t, managerExpectedNotifications, notificationsToTitlesList(t, resp.Notifications))
+ // Verify that we've reached the end of both lists.
+ require.Equal(t, "", resp.NextPageToken)
+
+ // Mark "auditor-8,manager-6" as clicked.
+ _, err = managerClient.UpsertUserNotificationState(ctx, managerUsername, ¬ificationsv1.UserNotificationState{
+ Spec: ¬ificationsv1.UserNotificationStateSpec{
+ NotificationId: notificationIdMap["auditor-8,manager-6"],
+ },
+ Status: ¬ificationsv1.UserNotificationStateStatus{
+ NotificationState: notificationsv1.NotificationState_NOTIFICATION_STATE_CLICKED,
+ },
+ })
+ require.NoError(t, err)
+
+ // Fetch notifications again and expect it to have the clicked label.
+ resp, err = managerClient.ListNotifications(ctx, ¬ificationsv1.ListNotificationsRequest{
+ PageSize: 10,
+ })
+ require.NoError(t, err)
+
+ clickedNotification := resp.Notifications[0] // "auditor-8,manager-6" is the first item in the list
+ clickedLabelValue := clickedNotification.GetMetadata().GetLabels()[types.NotificationClickedLabel]
+ require.Equal(t, "true", clickedLabelValue)
+
+ // Verify that manager can't upsert a notification state for auditor
+ _, err = managerClient.UpsertUserNotificationState(ctx, auditorUsername, ¬ificationsv1.UserNotificationState{
+ Spec: ¬ificationsv1.UserNotificationStateSpec{
+ NotificationId: notificationIdMap["auditor-7"],
+ },
+ Status: ¬ificationsv1.UserNotificationStateStatus{
+ NotificationState: notificationsv1.NotificationState_NOTIFICATION_STATE_DISMISSED,
+ },
+ })
+ require.Error(t, err)
+ require.True(t, trace.IsAccessDenied(err), "got error %T, expected an access denied error due to manager trying to upsert a notification state for a different user", err)
+
+ // Verify that manager can't uspert a user last seen notification for auditor.
+ _, err = managerClient.UpsertUserLastSeenNotification(ctx, auditorUsername, ¬ificationsv1.UserLastSeenNotification{
+ Status: ¬ificationsv1.UserLastSeenNotificationStatus{
+ LastSeenTime: lastSeenTimestamp,
+ },
+ })
+ require.Error(t, err)
+ require.True(t, trace.IsAccessDenied(err), "got error %T, expected an access denied error due to manager trying to upsert a last seen notification timestamp for a different user", err)
+}
+
+func newUserNotification(t *testing.T, username string, title string) *notificationsv1.Notification {
+ t.Helper()
+
+ notification := notificationsv1.Notification{
+ SubKind: "test-subkind",
+ Spec: ¬ificationsv1.NotificationSpec{
+ Username: username,
+ },
+ Metadata: &headerv1.Metadata{
+ Labels: map[string]string{
+ types.NotificationTitleLabel: title,
+ },
+ },
+ }
+
+ return ¬ification
+}
+
+func newGlobalNotification(t *testing.T, title string, spec *notificationsv1.GlobalNotificationSpec) *notificationsv1.GlobalNotification {
+ t.Helper()
+
+ spec.Notification = ¬ificationsv1.Notification{
+ SubKind: "test-subkind",
+ Spec: ¬ificationsv1.NotificationSpec{},
+ Metadata: &headerv1.Metadata{
+ Labels: map[string]string{
+ types.NotificationTitleLabel: title,
+ },
+ },
+ }
+
+ notification := notificationsv1.GlobalNotification{
+ Spec: spec,
+ }
+
+ return ¬ification
+}
+
+// notificationsToTitlesList accepts a list of notifications notifications and returns a slice of strings containing their titles in order, this is used to compare against
+// the expected outputs.
+func notificationsToTitlesList(t *testing.T, notifications []*notificationsv1.Notification) []string {
+ t.Helper()
+ var descriptions []string
+
+ for _, notif := range notifications {
+ description := notif.GetMetadata().GetLabels()[types.NotificationTitleLabel]
+ descriptions = append(descriptions, description)
+ }
+
+ return descriptions
+}
diff --git a/lib/auth/notifications/notificationsv1/service.go b/lib/auth/notifications/notificationsv1/service.go
new file mode 100644
index 00000000000..3abf265c22b
--- /dev/null
+++ b/lib/auth/notifications/notificationsv1/service.go
@@ -0,0 +1,446 @@
+// Copyright 2024 Gravitational, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package notifications
+
+import (
+ "context"
+ "fmt"
+ "log/slog"
+ "slices"
+ "strings"
+
+ "github.com/gravitational/trace"
+
+ "github.com/gravitational/teleport/api/client"
+ apidefaults "github.com/gravitational/teleport/api/defaults"
+ notificationsv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/notifications/v1"
+ "github.com/gravitational/teleport/api/internalutils/stream"
+ "github.com/gravitational/teleport/api/types"
+ "github.com/gravitational/teleport/lib/authz"
+ "github.com/gravitational/teleport/lib/services"
+)
+
+// ServiceConfig holds configuration options for the notifications gRPC service.
+type ServiceConfig struct {
+ // Backend is the interface containing all methods for backend read/writes.
+ Backend Backend
+
+ // Authorizer is the authorizer used to check access to resources.
+ Authorizer authz.Authorizer
+
+ // UserNotificationCache is a custom cache for user-specific notifications,
+ // this is to allow fetching notifications by date in descending order.
+ UserNotificationCache *services.UserNotificationCache
+
+ // GlobalNotificationCache is a custom cache for user-specific notifications,
+ // this is to allow fetching notifications by date in descending order.
+ GlobalNotificationCache *services.GlobalNotificationCache
+}
+
+// Backend contains the getters required for notification states and user last seen notifications,
+// as well as the methods required by the ReviewPermissionChecker.
+type Backend interface {
+ services.Notifications
+ // Needed by the ReviewPermissionChecker
+ services.UserLoginStatesGetter
+ services.UserGetter
+ services.RoleGetter
+ client.ListResourcesClient
+ GetRoles(ctx context.Context) ([]types.Role, error)
+ GetClusterName(opts ...services.MarshalOption) (types.ClusterName, error)
+}
+
+// Service implements the teleport.notifications.v1.NotificationsService RPC Service.
+type Service struct {
+ notificationsv1.UnimplementedNotificationServiceServer
+
+ authorizer authz.Authorizer
+ backend Backend
+ userNotificationCache *services.UserNotificationCache
+ globalNotificationCache *services.GlobalNotificationCache
+}
+
+// NewService returns a new notifications gRPC service.
+func NewService(cfg ServiceConfig) (*Service, error) {
+ switch {
+ case cfg.Backend == nil:
+ return nil, trace.BadParameter("backend is required")
+ case cfg.Authorizer == nil:
+ return nil, trace.BadParameter("authorizer is required")
+ case cfg.UserNotificationCache == nil:
+ return nil, trace.BadParameter("user notification cache is required")
+ case cfg.GlobalNotificationCache == nil:
+ return nil, trace.BadParameter("global notification cache is required")
+ }
+
+ return &Service{
+ authorizer: cfg.Authorizer,
+ backend: cfg.Backend,
+ userNotificationCache: cfg.UserNotificationCache,
+ globalNotificationCache: cfg.GlobalNotificationCache,
+ }, nil
+}
+
+// ListNotifications returns a paginated list of notifications which match the user.
+func (s *Service) ListNotifications(ctx context.Context, req *notificationsv1.ListNotificationsRequest) (*notificationsv1.ListNotificationsResponse, error) {
+ authCtx, err := s.authorizer.Authorize(ctx)
+ if err != nil {
+ return nil, trace.Wrap(err)
+ }
+
+ username := authCtx.User.GetName()
+
+ // Fetch all of the user's notification states. We do this upfront to filter out dismissed notifications.
+ notificationStatesMap := make(map[string]notificationsv1.NotificationState)
+ for startKey := ""; ; {
+ notificationStates, nextKey, err := s.backend.ListUserNotificationStates(ctx, username, apidefaults.DefaultChunkSize, startKey)
+ if err != nil {
+ return nil, trace.Wrap(err)
+ }
+ for _, notificationState := range notificationStates {
+ if notificationState.Spec != nil && notificationState.Status != nil {
+ notificationStatesMap[notificationState.Spec.NotificationId] = notificationState.Status.GetNotificationState()
+ }
+ }
+ if nextKey == "" {
+ break
+ }
+ startKey = nextKey
+ }
+
+ var userNotifMatchFn = func(n *notificationsv1.Notification) bool {
+ // Return true if the user hasn't dismissed this notification
+ return notificationStatesMap[n.GetMetadata().GetName()] != notificationsv1.NotificationState_NOTIFICATION_STATE_DISMISSED
+ }
+ userKey, globalKey, found := strings.Cut(req.PageToken, ",")
+ if !found && req.PageToken != "" {
+ return nil, trace.BadParameter("invalid page token provided")
+ }
+ pageSize := int(req.PageSize)
+ userNotifsStream := stream.Slice[*notificationsv1.Notification](nil)
+ if userKey != "" || !found {
+ userNotifsStream = stream.FilterMap(
+ s.userNotificationCache.StreamUserNotifications(ctx, username, userKey),
+ func(n *notificationsv1.Notification) (*notificationsv1.Notification, bool) {
+ if !userNotifMatchFn(n) {
+ return nil, false
+ }
+ return n, true
+ })
+ }
+ globalNotifsStream := stream.Slice[*notificationsv1.GlobalNotification](nil)
+ if globalKey != "" || !found {
+ globalNotifsStream = stream.FilterMap(
+ s.globalNotificationCache.StreamGlobalNotifications(ctx, globalKey),
+ func(gn *notificationsv1.GlobalNotification) (*notificationsv1.GlobalNotification, bool) {
+ if !s.matchGlobalNotification(ctx, authCtx, gn, notificationStatesMap) {
+ return nil, false
+ }
+ return gn, true
+ })
+ }
+ notifStream := stream.MergeStreams(
+ userNotifsStream,
+ globalNotifsStream,
+ isMoreRecent,
+ func(notification *notificationsv1.Notification) *notificationsv1.Notification {
+ return notification
+ },
+ func(globalNotification *notificationsv1.GlobalNotification) *notificationsv1.Notification {
+ notification := globalNotification.GetSpec().GetNotification()
+ notification.Metadata.Name = globalNotification.GetMetadata().GetName()
+ return notification
+ },
+ )
+ var notifications []*notificationsv1.Notification
+ var nextGlobalKey, nextUserKey string
+ for notifStream.Next() {
+ item := notifStream.Item()
+ if item != nil {
+ notifications = append(notifications, item)
+ }
+ if len(notifications) == pageSize {
+ // The nextKeys should represent the next unconsumed items in their respective lists.
+ // If the last item in this page (ie. the current item in the stream) was a user-specific notification, then the userNotificationsNextKey should be the next item in the userNotifsStream, and
+ // the globalNotificationsNextKey should be the current (and unconsumed) item in the globalNotifsStream. And vice-versa.
+ if item.GetMetadata().GetLabels()[types.NotificationScope] == "user" {
+ nextGlobalKey = globalNotifsStream.Item().GetMetadata().GetName()
+ // Advance to the next user-specific notification.
+ ok := userNotifsStream.Next()
+ if ok {
+ // If it exists, set it as the userNotificationsNextKey, otherwise set it to ""
+ nextUserKey = userNotifsStream.Item().GetMetadata().GetName()
+ } else {
+ nextUserKey = ""
+ }
+ } else {
+ nextUserKey = userNotifsStream.Item().GetMetadata().GetName()
+ // Advance to the next global notification.
+ ok := globalNotifsStream.Next()
+ if ok {
+ // If it exists, set it as the globalNotificationsNextKey.
+ nextGlobalKey = globalNotifsStream.Item().GetMetadata().GetName()
+ } else {
+ nextGlobalKey = ""
+ }
+ }
+ break
+ }
+ }
+ userLastSeenNotification, err := s.backend.GetUserLastSeenNotification(ctx, username)
+ if err != nil && !trace.IsNotFound(err) {
+ return nil, trace.Wrap(err)
+ }
+ // Add label to indicate notifications that the user has clicked.
+ for _, notification := range notifications {
+ if (notificationStatesMap[notification.GetMetadata().GetName()]) == notificationsv1.NotificationState_NOTIFICATION_STATE_CLICKED {
+ notification.GetMetadata().Labels[types.NotificationClickedLabel] = "true"
+ }
+ }
+ var nextPageToken string
+ if nextUserKey != "" || nextGlobalKey != "" {
+ nextPageToken = fmt.Sprintf("%s,%s", nextUserKey, nextGlobalKey)
+ }
+ response := ¬ificationsv1.ListNotificationsResponse{
+ Notifications: notifications,
+ NextPageToken: nextPageToken,
+ UserLastSeenNotificationTimestamp: userLastSeenNotification.GetStatus().GetLastSeenTime(),
+ }
+ return response, nil
+}
+
+func (s *Service) matchGlobalNotification(ctx context.Context, authCtx *authz.Context, gn *notificationsv1.GlobalNotification, notificationStatesMap map[string]notificationsv1.NotificationState) bool {
+ // If the user has dismissed this notification, return false.
+ if notificationStatesMap[gn.GetMetadata().GetName()] == notificationsv1.NotificationState_NOTIFICATION_STATE_DISMISSED {
+ return false
+ }
+
+ switch matcher := gn.Spec.Matcher.(type) {
+ case *notificationsv1.GlobalNotificationSpec_All:
+ // Always return true if the matcher is "all."
+ return true
+
+ case *notificationsv1.GlobalNotificationSpec_ByRoles:
+ matcherRoles := matcher.ByRoles.GetRoles()
+ userRoles := authCtx.User.GetRoles()
+
+ // If MatchAllConditions is true, then userRoles must contain every role in matcherRoles.
+ if gn.Spec.MatchAllConditions {
+ for _, matcherRole := range matcherRoles {
+ // Return false if there is any role missing.
+ if !slices.Contains(userRoles, matcherRole) {
+ return false
+ }
+ }
+ return true
+ }
+
+ // Return true if it matches at least one matcherRole.
+ for _, matcherRole := range matcherRoles {
+ if slices.Contains(userRoles, matcherRole) {
+ return true
+ }
+ }
+
+ return false
+
+ case *notificationsv1.GlobalNotificationSpec_ByPermissions:
+ roleConditionsList := matcher.ByPermissions.GetRoleConditions()
+
+ var results []bool
+ for _, roleConditions := range roleConditionsList {
+ match, err := s.matchRoleConditions(ctx, authCtx, roleConditions)
+ if err != nil {
+ slog.WarnContext(ctx, "Encountered error while matching RoleConditions", "role_conditions", roleConditions, "error", err)
+ return false
+ }
+
+ // If MatchAllConditions is false, we can exit at the first match.
+ if !gn.Spec.MatchAllConditions && match {
+ return true
+ }
+
+ // If MatchAllConditions is true, we exit at the first non-match.
+ if gn.Spec.MatchAllConditions && !match {
+ return false
+ }
+
+ results = append(results, match)
+ }
+
+ // Return false if any of the roleConditions didn't match.
+ if gn.Spec.MatchAllConditions {
+ return !slices.Contains(results, false)
+ }
+
+ return false
+ }
+
+ return false
+}
+
+func (s *Service) matchRoleConditions(ctx context.Context, authCtx *authz.Context, rc *types.RoleConditions) (bool, error) {
+ if len(rc.Logins) > 0 {
+ userLogins := authCtx.Checker.GetAllLogins()
+ var matchedLogin bool
+ for _, login := range rc.Logins {
+ // If at least one of the logins match, this is a match.
+ if slices.Contains(userLogins, login) {
+ matchedLogin = true
+ break
+ }
+ }
+ if !matchedLogin {
+ return false, nil
+ }
+ }
+
+ if len(rc.Rules) > 0 {
+ var matchedRule bool
+ for _, rule := range rc.Rules {
+ hasAccess, err := checkAccessToRule(authCtx, rule)
+ if err != nil {
+ return false, trace.Wrap(err, "encountered unexpected error when checking access to rule")
+ }
+
+ // If the user has permissions for at least one of the rules, this is a match.
+ if hasAccess {
+ matchedRule = true
+ break
+ }
+ }
+ if !matchedRule {
+ return false, nil
+ }
+ }
+
+ if rc.ReviewRequests != nil {
+ identity := authCtx.Identity.GetIdentity()
+ checker, err := services.NewReviewPermissionChecker(
+ ctx,
+ s.backend,
+ authCtx.User.GetName(),
+ &identity,
+ )
+ if err != nil {
+ return false, trace.Wrap(err)
+ }
+
+ // unless the user has allow directives for reviewing, they will never be able to
+ // see any requests other than their own.
+ if !checker.HasAllowDirectives() {
+ return false, nil
+ }
+
+ // We instantiate a fake access request with the defined roles, this allows us to use our existing AccessReviewChecker to check if the
+ // user is allowed to review requests for them.
+ fakeAccessRequest, err := types.NewAccessRequest("fake", "fake", rc.ReviewRequests.Roles...)
+ if err != nil {
+ return false, trace.Wrap(err)
+ }
+
+ canReview, err := checker.CanReviewRequest(fakeAccessRequest)
+ if err != nil {
+ return false, trace.Wrap(err, "failed to evaluate request review permissions")
+ }
+
+ if !canReview {
+ return false, nil
+ }
+ }
+
+ // This RoleConditions object matches if there were no failed matches that returned prior to this.
+ return true, nil
+}
+
+// checkAccessToRule returns true if the user has the permissions defined in a rule.
+func checkAccessToRule(authCtx *authz.Context, rule types.Rule) (bool, error) {
+ for _, resourceKind := range rule.Resources {
+ for _, verb := range rule.Verbs {
+ if err := authCtx.CheckAccessToKind(resourceKind, verb); err != nil {
+ // If the user doesn't have access for the verbs for any one of the resources in the rule, then just return false.
+ if trace.IsAccessDenied(err) {
+ return false, nil
+ // If the error is due to something else, then return it.
+ } else {
+ return false, trace.Wrap(err)
+ }
+ }
+ }
+ }
+
+ return true, nil
+}
+
+// isMoreRecent returns true if the userNotification is more recent than the globalNotification.
+func isMoreRecent(userNotification *notificationsv1.Notification, globalNotification *notificationsv1.GlobalNotification) bool {
+ userNotificationTime := userNotification.GetSpec().GetCreated().AsTime()
+ globalNotificationTime := globalNotification.GetSpec().GetNotification().GetSpec().GetCreated().AsTime()
+
+ return userNotificationTime.After(globalNotificationTime)
+}
+
+// UpsertUserNotificationState creates or updates a user notification state which records whether the user has clicked on or dismissed a notification.
+func (s *Service) UpsertUserNotificationState(ctx context.Context, req *notificationsv1.UpsertUserNotificationStateRequest) (*notificationsv1.UserNotificationState, error) {
+ if req.Username == "" {
+ return nil, trace.BadParameter("missing username")
+ }
+ if req.UserNotificationState == nil {
+ return nil, trace.BadParameter("missing notification state")
+ }
+
+ authCtx, err := s.authorizer.Authorize(ctx)
+ if err != nil {
+ return nil, trace.Wrap(err)
+ }
+ username := authCtx.User.GetName()
+ if username != req.Username {
+ return nil, trace.AccessDenied("a user may only update their own notification state")
+ }
+
+ out, err := s.backend.UpsertUserNotificationState(ctx, req.Username, req.UserNotificationState)
+ if err != nil {
+ return nil, trace.Wrap(err)
+ }
+
+ return out, nil
+}
+
+// UpsertUserLastSeenNotification creates or updates a user's last seen notification timestamp.
+func (s *Service) UpsertUserLastSeenNotification(ctx context.Context, req *notificationsv1.UpsertUserLastSeenNotificationRequest) (*notificationsv1.UserLastSeenNotification, error) {
+ if req.Username == "" {
+ return nil, trace.BadParameter("missing username")
+ }
+ if req.UserLastSeenNotification == nil {
+ return nil, trace.BadParameter("missing user last seen notification")
+ }
+
+ authCtx, err := s.authorizer.Authorize(ctx)
+ if err != nil {
+ return nil, trace.Wrap(err)
+ }
+
+ username := authCtx.User.GetName()
+ if username != req.Username {
+ return nil, trace.AccessDenied("a user may only update their own last seen notification timestamp")
+ }
+
+ out, err := s.backend.UpsertUserLastSeenNotification(ctx, req.Username, req.UserLastSeenNotification)
+ if err != nil {
+ return nil, trace.Wrap(err)
+ }
+
+ return out, nil
+}
diff --git a/lib/cache/cache_test.go b/lib/cache/cache_test.go
index 71379611e0d..ef62f812f33 100644
--- a/lib/cache/cache_test.go
+++ b/lib/cache/cache_test.go
@@ -3626,14 +3626,14 @@ func newUserNotification(t *testing.T, name string) *notificationsv1.Notificatio
Username: name,
},
Metadata: &headerv1.Metadata{
- Labels: map[string]string{"description": "test-description"},
+ Labels: map[string]string{types.NotificationTitleLabel: "test-title"},
},
}
return notification
}
-func newGlobalNotification(t *testing.T, description string) *notificationsv1.GlobalNotification {
+func newGlobalNotification(t *testing.T, title string) *notificationsv1.GlobalNotification {
t.Helper()
notification := ¬ificationsv1.GlobalNotification{
@@ -3645,7 +3645,7 @@ func newGlobalNotification(t *testing.T, description string) *notificationsv1.Gl
SubKind: "test-subkind",
Spec: ¬ificationsv1.NotificationSpec{},
Metadata: &headerv1.Metadata{
- Labels: map[string]string{"description": description},
+ Labels: map[string]string{types.NotificationTitleLabel: title},
},
},
},
diff --git a/lib/cache/collections.go b/lib/cache/collections.go
index c8d716b433d..339a014cdf4 100644
--- a/lib/cache/collections.go
+++ b/lib/cache/collections.go
@@ -3044,7 +3044,7 @@ func (userNotificationExecutor) delete(ctx context.Context, cache *Cache, resour
}
username := notification.GetSpec().GetUsername()
- notificationId := notification.GetSpec().GetId()
+ notificationId := notification.GetMetadata().GetName()
err := cache.notificationsCache.DeleteUserNotification(ctx, username, notificationId)
return trace.Wrap(err)
@@ -3107,7 +3107,7 @@ func (globalNotificationExecutor) delete(ctx context.Context, cache *Cache, reso
return trace.BadParameter("unknown Notification type, expected *notificationsv1.GlobalNotification, got %T", resource)
}
- notificationId := globalNotification.GetSpec().GetNotification().GetSpec().GetId()
+ notificationId := globalNotification.GetMetadata().GetName()
err := cache.notificationsCache.DeleteGlobalNotification(ctx, notificationId)
return trace.Wrap(err)
diff --git a/lib/services/local/events.go b/lib/services/local/events.go
index 9d0f04ef4c6..fa3b1d05d25 100644
--- a/lib/services/local/events.go
+++ b/lib/services/local/events.go
@@ -2049,7 +2049,6 @@ func (p *userNotificationParser) parse(event backend.Event) (types.Resource, err
Version: types.V1,
Spec: ¬ificationsv1.NotificationSpec{
Username: parts[2],
- Id: parts[3],
},
Metadata: &headerv1.Metadata{
Name: parts[3],
@@ -2100,9 +2099,7 @@ func (p *globalNotificationParser) parse(event backend.Event) (types.Resource, e
Version: types.V1,
Spec: ¬ificationsv1.GlobalNotificationSpec{
Notification: ¬ificationsv1.Notification{
- Spec: ¬ificationsv1.NotificationSpec{
- Id: parts[2],
- },
+ Spec: ¬ificationsv1.NotificationSpec{},
},
},
Metadata: &headerv1.Metadata{
diff --git a/lib/services/local/notifications.go b/lib/services/local/notifications.go
index d20726b2a5a..3fe337ac532 100644
--- a/lib/services/local/notifications.go
+++ b/lib/services/local/notifications.go
@@ -140,10 +140,7 @@ func (s *NotificationsService) CreateUserNotification(ctx context.Context, notif
if err != nil {
return nil, trace.Wrap(err)
}
- notification.Spec.Id = uuid.String()
-
- // We set this to the UUID because the service adapter uses `getName()` to determine the backend key to use when storing the notification.
- notification.Metadata.Name = notification.Spec.Id
+ notification.Metadata.Name = uuid.String()
if err := CheckAndSetExpiry(notification, s.clock); err != nil {
return nil, trace.Wrap(err)
@@ -151,6 +148,8 @@ func (s *NotificationsService) CreateUserNotification(ctx context.Context, notif
notification.Spec.Created = timestamppb.New(s.clock.Now())
+ notification.Metadata.Labels[types.NotificationScope] = "user"
+
// Append username prefix.
serviceWithPrefix := s.userNotificationService.WithPrefix(notification.Spec.Username)
@@ -165,7 +164,7 @@ func (s *NotificationsService) UpsertUserNotification(ctx context.Context, notif
}
// Precautionary check in case of accidental misuse.
- if notification.Spec.Id == "" {
+ if notification.Metadata.Name == "" {
return nil, trace.BadParameter("notification id is missing. Did you mean to use CreateUserNotification?")
}
@@ -230,10 +229,8 @@ func (s *NotificationsService) CreateGlobalNotification(ctx context.Context, glo
if err != nil {
return nil, trace.Wrap(err)
}
- globalNotification.Spec.Notification.Spec.Id = uuid.String()
-
- // We set this to the UUID because the service adapter uses `getName()` to determine the backend key to use when storing the notification.
- globalNotification.Metadata = &headerv1.Metadata{Name: globalNotification.Spec.Notification.Spec.Id}
+ globalNotification.Metadata = &headerv1.Metadata{Name: uuid.String()}
+ globalNotification.Spec.Notification.Metadata.Name = uuid.String()
if err := CheckAndSetExpiry(globalNotification.Spec.Notification, s.clock); err != nil {
return nil, trace.Wrap(err)
@@ -241,6 +238,8 @@ func (s *NotificationsService) CreateGlobalNotification(ctx context.Context, glo
globalNotification.Spec.Notification.Spec.Created = timestamppb.New(s.clock.Now())
+ globalNotification.Spec.Notification.Metadata.Labels[types.NotificationScope] = "global"
+
created, err := s.globalNotificationService.CreateResource(ctx, globalNotification)
return created, trace.Wrap(err)
}
@@ -252,7 +251,7 @@ func (s *NotificationsService) UpsertGlobalNotification(ctx context.Context, glo
}
// Precautionary check in case of accidental misuse.
- if globalNotification.Spec.Notification.Spec.Id == "" {
+ if globalNotification.Spec.Notification.Metadata.Name == "" {
return nil, trace.BadParameter("notification id is missing. Did you mean to use CreateGlobalNotification?")
}
@@ -274,8 +273,21 @@ func (s *NotificationsService) UpsertUserNotificationState(ctx context.Context,
// Verify that the notification this state is for exists.
notifServiceWithPrefix := s.userNotificationService.WithPrefix(username)
- if _, err := notifServiceWithPrefix.GetResource(ctx, state.Spec.NotificationId); err != nil {
- return nil, trace.Wrap(err)
+ _, err := notifServiceWithPrefix.GetResource(ctx, state.Spec.NotificationId)
+ if err != nil {
+ if !trace.IsNotFound(err) {
+ return nil, trace.Wrap(err)
+ }
+
+ // If we didn't find a user-specific notification with this ID, try finding a global notification.
+ _, err := s.globalNotificationService.GetResource(ctx, state.Spec.NotificationId)
+ if err != nil {
+ if !trace.IsNotFound(err) {
+ return nil, trace.Wrap(err)
+ }
+
+ return nil, trace.NotFound("notification '%s' does not exist", state.Spec.NotificationId)
+ }
}
state.Kind = types.KindUserNotificationState
diff --git a/lib/services/local/notifications_test.go b/lib/services/local/notifications_test.go
index 64d57115821..44501e73c27 100644
--- a/lib/services/local/notifications_test.go
+++ b/lib/services/local/notifications_test.go
@@ -32,6 +32,7 @@ import (
headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1"
notificationsv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/notifications/v1"
+ "github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/backend"
"github.com/gravitational/teleport/lib/backend/memory"
)
@@ -60,14 +61,14 @@ func TestUserNotificationCRUD(t *testing.T) {
notification, err := service.CreateUserNotification(ctx, userNotification1)
require.NoError(t, err)
require.Empty(t, cmp.Diff(userNotification1, notification, protocmp.Transform()))
- notification1Id := notification.Spec.Id
+ notification1Id := notification.GetMetadata().GetName()
// Prevent flakiness caused by notifications being created too close one after the other, which causes their UUID timestamps to be the same
// and the lexicographical ordering to possibly be wrong as it then relies on the random section of the UUID.
time.Sleep(250 * time.Millisecond)
notification, err = service.CreateUserNotification(ctx, userNotification2)
require.NoError(t, err)
require.Empty(t, cmp.Diff(userNotification2, notification, protocmp.Transform()))
- notification2Id := notification.Spec.Id
+ notification2Id := notification.GetMetadata().GetName()
// Test deleting a notification.
err = service.DeleteUserNotification(ctx, testUsername, notification1Id)
@@ -87,7 +88,7 @@ func TestUserNotificationCRUD(t *testing.T) {
userNotification1 = newUserNotification(t, testUsername, "test-notification-1")
_, err = service.CreateUserNotification(ctx, userNotification1)
require.NoError(t, err)
- notification1Id = notification.Spec.Id
+ notification1Id = notification.GetMetadata().GetName()
err = service.DeleteAllUserNotificationsForUser(ctx, testUsername)
require.NoError(t, err)
// Verify that the notifications don't exist anymore by attempting to delete them.
@@ -148,7 +149,7 @@ func TestGlobalNotificationCRUD(t *testing.T) {
notification, err := service.CreateGlobalNotification(ctx, globalNotification1)
require.NoError(t, err)
require.Empty(t, cmp.Diff(globalNotification1, notification, protocmp.Transform()))
- globalNotification1Id := notification.Spec.Notification.Spec.Id
+ globalNotification1Id := notification.GetMetadata().GetName()
notification, err = service.CreateGlobalNotification(ctx, globalNotification2)
require.NoError(t, err)
require.Empty(t, cmp.Diff(globalNotification2, notification, protocmp.Transform()))
@@ -188,13 +189,13 @@ func TestUserNotificationStateCRUD(t *testing.T) {
userNotification2 := newUserNotification(t, testUsername, "test-notification-2")
notification, err := service.CreateUserNotification(ctx, userNotification1)
require.NoError(t, err)
- notification1Id := notification.Spec.Id
+ notification1Id := notification.GetMetadata().GetName()
// Prevent flakiness caused by notifications being created too close one after the other, which causes their UUID timestamps to be the same
// and the lexicographical ordering to possibly be wrong as it then relies on the random section of the UUID.
time.Sleep(250 * time.Millisecond)
notification, err = service.CreateUserNotification(ctx, userNotification2)
require.NoError(t, err)
- notification2Id := notification.Spec.Id
+ notification2Id := notification.GetMetadata().GetName()
userNotificationState1 := ¬ificationsv1.UserNotificationState{
Spec: ¬ificationsv1.UserNotificationStateSpec{
@@ -374,7 +375,7 @@ func TestUserLastSeenNotificationCRUD(t *testing.T) {
require.True(t, trace.IsNotFound(err), "got error %T, expected a not found error due to user_last_seen_notification for test-username not existing", err)
}
-func newUserNotification(t *testing.T, username string, description string) *notificationsv1.Notification {
+func newUserNotification(t *testing.T, username string, title string) *notificationsv1.Notification {
t.Helper()
notification := notificationsv1.Notification{
@@ -383,14 +384,16 @@ func newUserNotification(t *testing.T, username string, description string) *not
Username: username,
},
Metadata: &headerv1.Metadata{
- Labels: map[string]string{"description": description},
+ Labels: map[string]string{
+ types.NotificationTitleLabel: title,
+ },
},
}
return ¬ification
}
-func newGlobalNotification(t *testing.T, description string) *notificationsv1.GlobalNotification {
+func newGlobalNotification(t *testing.T, title string) *notificationsv1.GlobalNotification {
t.Helper()
notification := notificationsv1.GlobalNotification{
@@ -402,7 +405,9 @@ func newGlobalNotification(t *testing.T, description string) *notificationsv1.Gl
SubKind: "test-subkind",
Spec: ¬ificationsv1.NotificationSpec{},
Metadata: &headerv1.Metadata{
- Labels: map[string]string{"description": description},
+ Labels: map[string]string{
+ types.NotificationTitleLabel: title,
+ },
},
},
},
diff --git a/lib/services/notifications.go b/lib/services/notifications.go
index ea2bb28d878..c3b094ea2bb 100644
--- a/lib/services/notifications.go
+++ b/lib/services/notifications.go
@@ -24,6 +24,7 @@ import (
"github.com/gravitational/trace"
notificationsv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/notifications/v1"
+ "github.com/gravitational/teleport/api/types"
)
// Notifications defines an interface for managing notifications.
@@ -62,8 +63,8 @@ func ValidateNotification(notification *notificationsv1.Notification) error {
return trace.BadParameter("notification metadata is missing")
}
- if notification.Metadata.Labels == nil {
- return trace.BadParameter("notification metadata labels are missing")
+ if _, exists := notification.Metadata.GetLabels()[types.NotificationTitleLabel]; !exists {
+ return trace.BadParameter("notification title label is missing")
}
return nil
diff --git a/lib/services/notifications_cache.go b/lib/services/notifications_cache.go
index 8b6a70c3c9a..5a4f2e75a99 100644
--- a/lib/services/notifications_cache.go
+++ b/lib/services/notifications_cache.go
@@ -205,6 +205,9 @@ func (c *UserNotificationCache) StreamUserNotifications(ctx context.Context, use
// Get the initial startKey if it wasn't provided.
if startKey == "" {
startKey = sortcache.NextKey(endKey)
+ } else {
+ // The sortcache expects the key to be in / format, so we prepend the username since the startKey passed into this function will just be a UUID.
+ startKey = fmt.Sprintf("%s/%s", username, startKey)
}
var done bool
@@ -266,7 +269,7 @@ func (c *UserNotificationCache) fetch(ctx context.Context) (*sortcache.SortCache
// GetUserSpecificKey returns the key for a user-specific notification in / format.
func GetUserSpecificKey(n *notificationsv1.Notification) string {
username := n.GetSpec().GetUsername()
- id := n.GetSpec().GetId()
+ id := n.GetMetadata().GetName()
return fmt.Sprintf("%s/%s", username, id)
}
diff --git a/lib/services/notifications_cache_test.go b/lib/services/notifications_cache_test.go
index 91f630ea7c1..a83b767a454 100644
--- a/lib/services/notifications_cache_test.go
+++ b/lib/services/notifications_cache_test.go
@@ -109,50 +109,50 @@ func TestUserNotificationsCache(t *testing.T) {
usernameB := "bob"
// Describe a set of mock user notifications to be created.
- // The number in the description represents the order in which they are created, eg. alice-1 is the first (and thus oldest) notification to be created for alice.
+ // The number in the title represents the order in which they are created, eg. alice-1 is the first (and thus oldest) notification to be created for alice.
testNotifications := []struct {
- username string
- description string
+ username string
+ title string
}{
{
- username: usernameB,
- description: "bob-1",
+ username: usernameB,
+ title: "bob-1",
},
{
- username: usernameB,
- description: "bob-2",
+ username: usernameB,
+ title: "bob-2",
},
{
- username: usernameA,
- description: "alice-1",
+ username: usernameA,
+ title: "alice-1",
},
{
- username: usernameB,
- description: "bob-3",
+ username: usernameB,
+ title: "bob-3",
},
{
- username: usernameB,
- description: "bob-4",
+ username: usernameB,
+ title: "bob-4",
},
{
- username: usernameA,
- description: "alice-2",
+ username: usernameA,
+ title: "alice-2",
},
{
- username: usernameA,
- description: "alice-3",
+ username: usernameA,
+ title: "alice-3",
},
{
- username: usernameA,
- description: "alice-4",
+ username: usernameA,
+ title: "alice-4",
},
{
- username: usernameB,
- description: "bob-5",
+ username: usernameB,
+ title: "bob-5",
},
{
- username: usernameA,
- description: "alice-5",
+ username: usernameA,
+ title: "alice-5",
},
}
@@ -164,7 +164,7 @@ func TestUserNotificationsCache(t *testing.T) {
for _, n := range testNotifications {
// We add a delay to ensure that the timestamps in the generated UUID's are all different and in the correct order.
time.Sleep(50 * time.Millisecond)
- notification := newUserNotification(t, n.username, n.description)
+ notification := newUserNotification(t, n.username, n.title)
// Create the notification in the backend.
created, err := svcs.CreateUserNotification(ctx, notification)
require.NoError(t, err)
@@ -205,41 +205,41 @@ func TestUserNotificationsCache(t *testing.T) {
streamA.Next()
streamA.Next()
streamA.Next()
- usernameAThirdItemStartKey = services.GetUserSpecificKey(streamA.Item())
+ usernameAThirdItemStartKey = streamA.Item().GetMetadata().GetName()
var usernameBThirdItemStartKey string
streamB := cache.StreamUserNotifications(ctx, usernameB, "")
streamB.Next()
streamB.Next()
streamB.Next()
- usernameBThirdItemStartKey = services.GetUserSpecificKey(streamB.Item())
+ usernameBThirdItemStartKey = streamB.Item().GetMetadata().GetName()
testCases := []struct {
- testName string
- username string
- startKey string
- expectedNotificationDescriptions []string
+ testName string
+ username string
+ startKey string
+ expectedNotificationTitles []string
}{
{
testName: "correctly fetches sorted notifications for usernameA with no startKey",
username: usernameA,
// Since alice-1 is the oldest, it should be at the end of the list.
- expectedNotificationDescriptions: []string{"alice-5", "alice-4", "alice-3", "alice-2", "alice-1"},
+ expectedNotificationTitles: []string{"alice-5", "alice-4", "alice-3", "alice-2", "alice-1"},
},
{
- testName: "correctly fetches sorted notifications for usernameB with no startKey",
- username: usernameB,
- expectedNotificationDescriptions: []string{"bob-5", "bob-4", "bob-3", "bob-2", "bob-1"},
+ testName: "correctly fetches sorted notifications for usernameB with no startKey",
+ username: usernameB,
+ expectedNotificationTitles: []string{"bob-5", "bob-4", "bob-3", "bob-2", "bob-1"},
}, {
- testName: "correctly fetches sorted notifications for usernameA with a startKey",
- username: usernameA,
- startKey: usernameAThirdItemStartKey,
- expectedNotificationDescriptions: []string{"alice-3", "alice-2", "alice-1"},
+ testName: "correctly fetches sorted notifications for usernameA with a startKey",
+ username: usernameA,
+ startKey: usernameAThirdItemStartKey,
+ expectedNotificationTitles: []string{"alice-3", "alice-2", "alice-1"},
}, {
- testName: "correctly fetches sorted notifications for usernameB with a startKey",
- username: usernameB,
- startKey: usernameBThirdItemStartKey,
- expectedNotificationDescriptions: []string{"bob-3", "bob-2", "bob-1"},
+ testName: "correctly fetches sorted notifications for usernameB with a startKey",
+ username: usernameB,
+ startKey: usernameBThirdItemStartKey,
+ expectedNotificationTitles: []string{"bob-3", "bob-2", "bob-1"},
},
}
@@ -248,11 +248,11 @@ func TestUserNotificationsCache(t *testing.T) {
var out []string
notifsStream := cache.StreamUserNotifications(ctx, tc.username, tc.startKey)
for notifsStream.Next() {
- desc := notifsStream.Item().GetMetadata().GetLabels()["description"]
- out = append(out, desc)
+ title := notifsStream.Item().GetMetadata().GetLabels()[types.NotificationTitleLabel]
+ out = append(out, title)
}
notifsStream.Done()
- require.Equal(t, tc.expectedNotificationDescriptions, out)
+ require.Equal(t, tc.expectedNotificationTitles, out)
})
}
@@ -303,8 +303,8 @@ func TestUserNotificationsCache(t *testing.T) {
expected := []string{"alice-3", "alice-2", "alice-1"}
notifsStream := cache.StreamUserNotifications(ctx, usernameA, "")
for notifsStream.Next() {
- desc := notifsStream.Item().GetMetadata().GetLabels()["description"]
- out = append(out, desc)
+ title := notifsStream.Item().GetMetadata().GetLabels()[types.NotificationTitleLabel]
+ out = append(out, title)
}
notifsStream.Done()
require.Equal(t, expected, out)
@@ -320,7 +320,7 @@ func TestGlobalNotificationsCache(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
- testNotificationDescriptions := []string{
+ testNotificationTitles := []string{
"gn-1",
"gn-2",
"gn-3",
@@ -332,7 +332,7 @@ func TestGlobalNotificationsCache(t *testing.T) {
var notificationIds []string
// Create the notifications, with a 50ms delay between each one.
- for _, gn := range testNotificationDescriptions {
+ for _, gn := range testNotificationTitles {
time.Sleep(50 * time.Millisecond)
notification := newGlobalNotification(t, gn)
// Create the notification in the backend.
@@ -350,7 +350,7 @@ func TestGlobalNotificationsCache(t *testing.T) {
require.NoError(t, err)
gnStream.Done()
- if len(collectedStream) == len(testNotificationDescriptions) {
+ if len(collectedStream) == len(testNotificationTitles) {
break
}
@@ -375,8 +375,8 @@ func TestGlobalNotificationsCache(t *testing.T) {
expected := []string{"gn-5", "gn-4", "gn-3", "gn-2", "gn-1"}
gnStream = cache.StreamGlobalNotifications(ctx, "")
for gnStream.Next() {
- desc := gnStream.Item().GetSpec().GetNotification().GetMetadata().GetLabels()["description"]
- out = append(out, desc)
+ title := gnStream.Item().GetSpec().GetNotification().GetMetadata().GetLabels()[types.NotificationTitleLabel]
+ out = append(out, title)
}
require.Equal(t, expected, out)
gnStream.Done()
@@ -386,8 +386,8 @@ func TestGlobalNotificationsCache(t *testing.T) {
expected = []string{"gn-3", "gn-2", "gn-1"}
gnStream = cache.StreamGlobalNotifications(ctx, thirdItemStartKey)
for gnStream.Next() {
- desc := gnStream.Item().GetSpec().GetNotification().GetMetadata().GetLabels()["description"]
- out = append(out, desc)
+ title := gnStream.Item().GetSpec().GetNotification().GetMetadata().GetLabels()[types.NotificationTitleLabel]
+ out = append(out, title)
}
require.Equal(t, expected, out)
gnStream.Done()
@@ -420,7 +420,7 @@ func TestGlobalNotificationsCache(t *testing.T) {
}
}
-func newUserNotification(t *testing.T, username string, description string) *notificationsv1.Notification {
+func newUserNotification(t *testing.T, username string, title string) *notificationsv1.Notification {
t.Helper()
notification := notificationsv1.Notification{
@@ -429,14 +429,16 @@ func newUserNotification(t *testing.T, username string, description string) *not
Username: username,
},
Metadata: &headerv1.Metadata{
- Labels: map[string]string{"description": description},
+ Labels: map[string]string{
+ types.NotificationTitleLabel: title,
+ },
},
}
return ¬ification
}
-func newGlobalNotification(t *testing.T, description string) *notificationsv1.GlobalNotification {
+func newGlobalNotification(t *testing.T, title string) *notificationsv1.GlobalNotification {
t.Helper()
notification := notificationsv1.GlobalNotification{
@@ -448,7 +450,9 @@ func newGlobalNotification(t *testing.T, description string) *notificationsv1.Gl
SubKind: "test-subkind",
Spec: ¬ificationsv1.NotificationSpec{},
Metadata: &headerv1.Metadata{
- Labels: map[string]string{"description": description},
+ Labels: map[string]string{
+ types.NotificationTitleLabel: title,
+ },
},
},
},
diff --git a/lib/services/notifications_test.go b/lib/services/notifications_test.go
index 70e2c264663..e199a928c20 100644
--- a/lib/services/notifications_test.go
+++ b/lib/services/notifications_test.go
@@ -38,11 +38,10 @@ func TestMarshalNotificationRoundTrip(t *testing.T) {
Kind: types.KindNotification,
Version: types.V1,
SubKind: "test-subkind",
- Spec: ¬ificationsv1.NotificationSpec{
- Id: "test-notification-1",
- },
+ Spec: ¬ificationsv1.NotificationSpec{},
Metadata: &headerv1.Metadata{
- Labels: map[string]string{"description": "description-1"},
+ Name: "test-notification-1",
+ Labels: map[string]string{types.NotificationTitleLabel: "title-1"},
},
}
@@ -67,11 +66,10 @@ func TestMarshalGlobalNotificationRoundTrip(t *testing.T) {
},
Notification: ¬ificationsv1.Notification{
SubKind: "test-subkind",
- Spec: ¬ificationsv1.NotificationSpec{
- Id: "test-notification-id",
- },
+ Spec: ¬ificationsv1.NotificationSpec{},
Metadata: &headerv1.Metadata{
- Labels: map[string]string{"description": "description-1"},
+ Name: "test-notification-id",
+ Labels: map[string]string{types.NotificationTitleLabel: "title-1"},
},
},
},