From 7b54a19060e5042194d39698cd295eab340e9a0b Mon Sep 17 00:00:00 2001 From: Nicholas Cristofaro Date: Mon, 11 Dec 2023 17:53:39 -0300 Subject: [PATCH 1/9] is: Add organization notification fanout migration --- ..._organization_notification_fanout.down.sql | 16 ++++++++++++++ ...00_organization_notification_fanout.up.sql | 22 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 pkg/identityserver/store/migrations/20231211000000_organization_notification_fanout.down.sql create mode 100644 pkg/identityserver/store/migrations/20231211000000_organization_notification_fanout.up.sql diff --git a/pkg/identityserver/store/migrations/20231211000000_organization_notification_fanout.down.sql b/pkg/identityserver/store/migrations/20231211000000_organization_notification_fanout.down.sql new file mode 100644 index 0000000000..84114e3c21 --- /dev/null +++ b/pkg/identityserver/store/migrations/20231211000000_organization_notification_fanout.down.sql @@ -0,0 +1,16 @@ +ALTER TABLE organizations +DROP COLUMN IF EXISTS fanout_notifications CASCADE; + +--bun:split +CREATE OR REPLACE VIEW organization_accounts AS +SELECT + acc.id AS account_id, + acc.created_at AS account_created_at, + acc.updated_at AS account_updated_at, + acc.deleted_at AS account_deleted_at, + acc.uid AS account_uid, + org.* +FROM + accounts acc + JOIN organizations org ON org.id = acc.account_id + AND acc.account_type = 'organization'; diff --git a/pkg/identityserver/store/migrations/20231211000000_organization_notification_fanout.up.sql b/pkg/identityserver/store/migrations/20231211000000_organization_notification_fanout.up.sql new file mode 100644 index 0000000000..7ccf8dbc75 --- /dev/null +++ b/pkg/identityserver/store/migrations/20231211000000_organization_notification_fanout.up.sql @@ -0,0 +1,22 @@ +ALTER TABLE + organizations +ADD + COLUMN IF NOT EXISTS fanout_notifications BOOLEAN; + +--bun:split +UPDATE organizations SET fanout_notifications = TRUE; + +--bun:split +CREATE +OR REPLACE VIEW organization_accounts AS +SELECT + acc.id AS account_id, + acc.created_at AS account_created_at, + acc.updated_at AS account_updated_at, + acc.deleted_at AS account_deleted_at, + acc.uid AS account_uid, + org.* +FROM + accounts acc + JOIN organizations org ON org.id = acc.account_id + AND acc.account_type = 'organization'; From 6eb40585a954d8c8373a266673e42da69968bc10 Mon Sep 17 00:00:00 2001 From: Nicholas Cristofaro Date: Mon, 11 Dec 2023 17:55:47 -0300 Subject: [PATCH 2/9] api: Update organization message definition --- api/ttn/lorawan/v3/api.md | 1 + api/ttn/lorawan/v3/api.swagger.json | 8 + api/ttn/lorawan/v3/organization.proto | 6 +- pkg/ttnpb/organization.pb.go | 397 ++++++++++++------------ pkg/ttnpb/organization.pb.paths.fm.go | 4 + pkg/ttnpb/organization.pb.setters.fm.go | 10 + pkg/ttnpb/organization.pb.validate.go | 2 + pkg/ttnpb/organization_flags.pb.go | 13 + pkg/ttnpb/organization_json.pb.go | 8 + sdk/js/generated/api-definition.json | 4 + sdk/js/generated/api.json | 12 + 11 files changed, 272 insertions(+), 193 deletions(-) diff --git a/api/ttn/lorawan/v3/api.md b/api/ttn/lorawan/v3/api.md index 64a11f64cf..3858c6d751 100644 --- a/api/ttn/lorawan/v3/api.md +++ b/api/ttn/lorawan/v3/api.md @@ -9236,6 +9236,7 @@ is used to manage OAuth client authorizations for users. | `contact_info` | [`ContactInfo`](#ttn.lorawan.v3.ContactInfo) | repeated | Contact information for this organization. Typically used to indicate who to contact with security/billing questions about the organization. This field is deprecated. Use administrative_contact and technical_contact instead. | | `administrative_contact` | [`OrganizationOrUserIdentifiers`](#ttn.lorawan.v3.OrganizationOrUserIdentifiers) | | | | `technical_contact` | [`OrganizationOrUserIdentifiers`](#ttn.lorawan.v3.OrganizationOrUserIdentifiers) | | | +| `fanout_notifications` | [`bool`](#bool) | | Determines if a notification will be sent to the collaborators. If false it, notifications will be sent only to the administrative or technical contact. | #### Field Rules diff --git a/api/ttn/lorawan/v3/api.swagger.json b/api/ttn/lorawan/v3/api.swagger.json index 5fd8a1f5f9..92c8d032d4 100644 --- a/api/ttn/lorawan/v3/api.swagger.json +++ b/api/ttn/lorawan/v3/api.swagger.json @@ -13811,6 +13811,10 @@ }, "technical_contact": { "$ref": "#/definitions/v3OrganizationOrUserIdentifiers" + }, + "fanout_notifications": { + "type": "boolean", + "description": "Determines if a notification will be sent to the collaborators. If false it, notifications will be sent only to the\nadministrative or technical contact." } } }, @@ -25609,6 +25613,10 @@ }, "technical_contact": { "$ref": "#/definitions/v3OrganizationOrUserIdentifiers" + }, + "fanout_notifications": { + "type": "boolean", + "description": "Determines if a notification will be sent to the collaborators. If false it, notifications will be sent only to the\nadministrative or technical contact." } } }, diff --git a/api/ttn/lorawan/v3/organization.proto b/api/ttn/lorawan/v3/organization.proto index b3949fe55a..4fbb1fed89 100644 --- a/api/ttn/lorawan/v3/organization.proto +++ b/api/ttn/lorawan/v3/organization.proto @@ -91,7 +91,11 @@ message Organization { reserved 13; reserved "gateway_limit"; - // next: 14 + // Determines if a notification will be sent to the collaborators. If false it, notifications will be sent only to the + // administrative or technical contact. + bool fanout_notifications = 14; + + // next: 15 } message Organizations { diff --git a/pkg/ttnpb/organization.pb.go b/pkg/ttnpb/organization.pb.go index 879ed25149..8a7d548f7f 100644 --- a/pkg/ttnpb/organization.pb.go +++ b/pkg/ttnpb/organization.pb.go @@ -64,6 +64,9 @@ type Organization struct { ContactInfo []*ContactInfo `protobuf:"bytes,7,rep,name=contact_info,json=contactInfo,proto3" json:"contact_info,omitempty"` AdministrativeContact *OrganizationOrUserIdentifiers `protobuf:"bytes,9,opt,name=administrative_contact,json=administrativeContact,proto3" json:"administrative_contact,omitempty"` TechnicalContact *OrganizationOrUserIdentifiers `protobuf:"bytes,10,opt,name=technical_contact,json=technicalContact,proto3" json:"technical_contact,omitempty"` + // Determines if a notification will be sent to the collaborators. If false it, notifications will be sent only to the + // administrative or technical contact. + FanoutNotifications bool `protobuf:"varint,14,opt,name=fanout_notifications,json=fanoutNotifications,proto3" json:"fanout_notifications,omitempty"` } func (x *Organization) Reset() { @@ -169,6 +172,13 @@ func (x *Organization) GetTechnicalContact() *OrganizationOrUserIdentifiers { return nil } +func (x *Organization) GetFanoutNotifications() bool { + if x != nil { + return x.FanoutNotifications + } + return false +} + type Organizations struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1066,7 +1076,7 @@ var file_ttn_lorawan_v3_organization_proto_rawDesc = []byte{ 0x74, 0x74, 0x6e, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2f, 0x76, 0x33, 0x2f, 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x92, 0x07, 0x0a, 0x0c, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc5, 0x07, 0x0a, 0x0c, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4b, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, @@ -1114,212 +1124,215 @@ var file_ttn_lorawan_v3_organization_proto_rawDesc = []byte{ 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x10, 0x74, 0x65, - 0x63, 0x68, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x1a, 0x3d, - 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x08, 0xf2, - 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x4a, 0x04, 0x08, 0x0b, 0x10, 0x0c, 0x4a, 0x04, 0x08, - 0x0c, 0x10, 0x0d, 0x4a, 0x04, 0x08, 0x0d, 0x10, 0x0e, 0x52, 0x11, 0x61, 0x70, 0x70, 0x6c, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x0c, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x0d, 0x67, 0x61, 0x74, 0x65, - 0x77, 0x61, 0x79, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x53, 0x0a, 0x0d, 0x4f, 0x72, 0x67, - 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x42, 0x0a, 0x0d, 0x6f, 0x72, - 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x0d, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xb1, - 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5c, 0x0a, 0x10, 0x6f, 0x72, 0x67, - 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, - 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, - 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, - 0x5f, 0x6d, 0x61, 0x73, 0x6b, 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, 0x46, 0x69, - 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, - 0x73, 0x6b, 0x22, 0xf0, 0x02, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x72, 0x67, 0x61, 0x6e, - 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x59, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x4f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x69, 0x65, 0x72, 0x73, 0x42, 0x06, 0xf2, 0xaa, 0x19, 0x02, 0x28, 0x01, 0x52, 0x0c, 0x63, 0x6f, - 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, + 0x63, 0x68, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x12, 0x31, + 0x0a, 0x14, 0x66, 0x61, 0x6e, 0x6f, 0x75, 0x74, 0x5f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x66, 0x61, + 0x6e, 0x6f, 0x75, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x4a, 0x04, 0x08, 0x0b, 0x10, 0x0c, + 0x4a, 0x04, 0x08, 0x0c, 0x10, 0x0d, 0x4a, 0x04, 0x08, 0x0d, 0x10, 0x0e, 0x52, 0x11, 0x61, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, + 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x0d, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x53, 0x0a, 0x0d, + 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x42, 0x0a, + 0x0d, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, + 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x0d, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x22, 0xb1, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5c, 0x0a, 0x10, + 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, 0x6f, 0x72, 0x67, 0x61, 0x6e, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 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, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, - 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x66, 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x50, 0xfa, 0x42, 0x4d, 0x72, 0x4b, 0x52, 0x00, 0x52, 0x0f, 0x6f, - 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x52, 0x10, - 0x2d, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x05, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x0a, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x0b, 0x2d, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x0a, - 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, - 0x05, 0x2a, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x12, 0x0a, - 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x61, 0x67, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x3a, 0x08, 0xf2, 0xaa, 0x19, - 0x04, 0x08, 0x00, 0x10, 0x01, 0x22, 0xc4, 0x01, 0x0a, 0x19, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x4a, 0x0a, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, - 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, - 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, - 0x01, 0x52, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x5b, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0xf0, 0x02, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x72, + 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x59, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x06, 0xf2, 0xaa, 0x19, 0x02, 0x28, 0x01, 0x52, + 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x39, 0x0a, + 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 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, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x66, 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, + 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x50, 0xfa, 0x42, 0x4d, 0x72, 0x4b, 0x52, 0x00, + 0x52, 0x0f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, + 0x64, 0x52, 0x10, 0x2d, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x05, 0x2d, 0x6e, 0x61, 0x6d, 0x65, + 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x0b, 0x2d, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, + 0x12, 0x1e, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, + 0x70, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x3a, 0x08, + 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x01, 0x22, 0xc4, 0x01, 0x0a, 0x19, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4a, 0x0a, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, + 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, + 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x5b, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, + 0x01, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x22, + 0xa2, 0x01, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4a, 0x0a, + 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x6f, 0x72, 0x67, + 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 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, + 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x4d, 0x61, 0x73, 0x6b, 0x22, 0xb3, 0x02, 0x0a, 0x1e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x72, 0x67, + 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5c, 0x0a, 0x10, 0x6f, 0x72, 0x67, 0x61, 0x6e, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, + 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x75, 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x5f, 0xfa, 0x42, 0x5c, 0x72, 0x5a, 0x52, 0x00, 0x52, 0x0a, 0x61, + 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x52, 0x0b, 0x2d, 0x61, 0x70, 0x69, 0x5f, + 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x05, 0x2d, 0x6e, + 0x61, 0x6d, 0x65, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, + 0x0b, 0x2d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x0a, 0x65, 0x78, + 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x52, 0x0b, 0x2d, 0x65, 0x78, 0x70, 0x69, 0x72, + 0x65, 0x73, 0x5f, 0x61, 0x74, 0x52, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x05, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, + 0x2a, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x12, 0x0a, 0x04, + 0x70, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, + 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x01, 0x22, 0x93, 0x01, 0x0a, 0x1c, 0x47, + 0x65, 0x74, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x50, + 0x49, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5c, 0x0a, 0x10, 0x6f, + 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x4f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, - 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x22, 0xa2, 0x01, 0x0a, - 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4a, 0x0a, 0x0c, 0x6f, 0x72, - 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x08, - 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, - 0x6d, 0x61, 0x73, 0x6b, 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, 0x46, 0x69, 0x65, - 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, - 0x6b, 0x22, 0xb3, 0x02, 0x0a, 0x1e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, + 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x6b, 0x65, 0x79, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6b, 0x65, 0x79, 0x49, 0x64, + 0x22, 0xa3, 0x02, 0x0a, 0x1f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x67, 0x61, 0x6e, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5c, 0x0a, 0x10, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x73, 0x12, 0x75, 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x5f, 0xfa, 0x42, 0x5c, 0x72, 0x5a, 0x52, 0x00, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x5f, - 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x52, 0x0b, 0x2d, 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, - 0x5f, 0x69, 0x64, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x05, 0x2d, 0x6e, 0x61, 0x6d, 0x65, - 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x0b, 0x2d, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, - 0x65, 0x73, 0x5f, 0x61, 0x74, 0x52, 0x0b, 0x2d, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, - 0x61, 0x74, 0x52, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x05, 0x6c, 0x69, 0x6d, - 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, - 0xe8, 0x07, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x3a, 0x08, 0xf2, - 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x01, 0x22, 0x93, 0x01, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x4f, - 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x50, 0x49, 0x4b, 0x65, - 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5c, 0x0a, 0x10, 0x6f, 0x72, 0x67, 0x61, + 0x64, 0x73, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x40, 0x0a, 0x06, 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0e, 0x32, + 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x52, 0x69, 0x67, 0x68, 0x74, 0x42, 0x11, 0xfa, 0x42, 0x0e, 0x92, 0x01, 0x0b, 0x08, 0x01, + 0x18, 0x01, 0x22, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x06, 0x72, 0x69, 0x67, 0x68, 0x74, + 0x73, 0x12, 0x43, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 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, 0x42, 0x08, 0xfa, 0x42, 0x05, 0xb2, 0x01, 0x02, 0x40, 0x01, 0x52, 0x09, 0x65, 0x78, 0x70, + 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x22, 0xf5, 0x01, 0x0a, 0x1f, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x50, 0x49, + 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5c, 0x0a, 0x10, 0x6f, 0x72, + 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, + 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, + 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x61, 0x70, 0x69, 0x5f, + 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x50, 0x49, 0x4b, 0x65, + 0x79, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x06, 0x61, 0x70, 0x69, + 0x4b, 0x65, 0x79, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, + 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, + 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x96, + 0x01, 0x0a, 0x1f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x5c, 0x0a, 0x10, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, + 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, + 0x0f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, + 0x12, 0x15, 0x0a, 0x06, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x6b, 0x65, 0x79, 0x49, 0x64, 0x22, 0xf1, 0x01, 0x0a, 0x24, 0x4c, 0x69, 0x73, 0x74, + 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6c, 0x6c, + 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x5c, 0x0a, 0x10, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, + 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, 0x6f, + 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x1e, + 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, + 0x42, 0x05, 0x2a, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x61, + 0x67, 0x65, 0x12, 0x37, 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x21, 0xfa, 0x42, 0x1e, 0x72, 0x1c, 0x52, 0x00, 0x52, 0x02, 0x69, 0x64, 0x52, 0x03, + 0x2d, 0x69, 0x64, 0x52, 0x07, 0x2d, 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x52, 0x06, 0x72, 0x69, + 0x67, 0x68, 0x74, 0x73, 0x52, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x22, 0xdf, 0x01, 0x0a, 0x22, + 0x47, 0x65, 0x74, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, + 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x5c, 0x0a, 0x10, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, + 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, + 0x0f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, + 0x12, 0x5b, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, + 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x22, 0xce, 0x01, + 0x0a, 0x22, 0x53, 0x65, 0x74, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x5c, 0x0a, 0x10, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, + 0x01, 0x52, 0x0f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x73, 0x12, 0x4a, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x62, + 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, + 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x22, 0xe9, + 0x01, 0x0a, 0x25, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5c, 0x0a, 0x10, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6b, 0x65, 0x79, 0x49, 0x64, 0x22, 0xa3, 0x02, - 0x0a, 0x1f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x5c, 0x0a, 0x10, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, - 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, - 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, - 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, - 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, - 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x40, 0x0a, 0x06, - 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, - 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x69, - 0x67, 0x68, 0x74, 0x42, 0x11, 0xfa, 0x42, 0x0e, 0x92, 0x01, 0x0b, 0x08, 0x01, 0x18, 0x01, 0x22, - 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x06, 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x12, 0x43, - 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 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, 0x42, 0x08, - 0xfa, 0x42, 0x05, 0xb2, 0x01, 0x02, 0x40, 0x01, 0x52, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, - 0x73, 0x41, 0x74, 0x22, 0xf5, 0x01, 0x0a, 0x1f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x72, - 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5c, 0x0a, 0x10, 0x6f, 0x72, 0x67, 0x61, 0x6e, - 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, - 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x07, 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x42, 0x08, - 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x06, 0x61, 0x70, 0x69, 0x4b, 0x65, 0x79, - 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, - 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x96, 0x01, 0x0a, 0x1f, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x5c, 0x0a, 0x10, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, - 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, - 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, - 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, 0x6f, 0x72, - 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x15, 0x0a, - 0x06, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6b, - 0x65, 0x79, 0x49, 0x64, 0x22, 0xf1, 0x01, 0x0a, 0x24, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x72, 0x67, - 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, - 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5c, 0x0a, - 0x10, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, - 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, - 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, 0x6f, 0x72, 0x67, 0x61, - 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x1e, 0x0a, 0x05, 0x6c, - 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, - 0x03, 0x18, 0xe8, 0x07, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, - 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, - 0x37, 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, - 0xfa, 0x42, 0x1e, 0x72, 0x1c, 0x52, 0x00, 0x52, 0x02, 0x69, 0x64, 0x52, 0x03, 0x2d, 0x69, 0x64, - 0x52, 0x07, 0x2d, 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x52, 0x06, 0x72, 0x69, 0x67, 0x68, 0x74, - 0x73, 0x52, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x22, 0xdf, 0x01, 0x0a, 0x22, 0x47, 0x65, 0x74, - 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6c, 0x6c, - 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x5c, 0x0a, 0x10, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, - 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, - 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, - 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, 0x6f, 0x72, - 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x5b, 0x0a, - 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, - 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x4f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, - 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x63, 0x6f, - 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x22, 0xce, 0x01, 0x0a, 0x22, 0x53, - 0x65, 0x74, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, - 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x5c, 0x0a, 0x10, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, - 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x67, - 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, - 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, - 0x4a, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, - 0x74, 0x6f, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x63, - 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x22, 0xe9, 0x01, 0x0a, 0x25, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5c, 0x0a, 0x10, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, - 0x10, 0x01, 0x52, 0x0f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x64, 0x73, 0x12, 0x62, 0x0a, 0x10, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, - 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4f, - 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x72, 0x55, 0x73, 0x65, - 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, - 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, - 0x61, 0x74, 0x6f, 0x72, 0x49, 0x64, 0x73, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x6f, 0x2e, 0x74, 0x68, - 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, - 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x76, 0x33, - 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x74, 0x6e, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x62, 0x0a, 0x10, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, + 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x72, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, 0x63, 0x6f, 0x6c, 0x6c, 0x61, + 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x64, 0x73, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x6f, + 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, + 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x74, 0x6e, 0x70, 0x62, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/pkg/ttnpb/organization.pb.paths.fm.go b/pkg/ttnpb/organization.pb.paths.fm.go index 6b7135fad0..54eaf7e9ef 100644 --- a/pkg/ttnpb/organization.pb.paths.fm.go +++ b/pkg/ttnpb/organization.pb.paths.fm.go @@ -15,6 +15,7 @@ var OrganizationFieldPathsNested = []string{ "created_at", "deleted_at", "description", + "fanout_notifications", "ids", "ids.organization_id", "name", @@ -35,6 +36,7 @@ var OrganizationFieldPathsTopLevel = []string{ "created_at", "deleted_at", "description", + "fanout_notifications", "ids", "name", "technical_contact", @@ -101,6 +103,7 @@ var CreateOrganizationRequestFieldPathsNested = []string{ "organization.created_at", "organization.deleted_at", "organization.description", + "organization.fanout_notifications", "organization.ids", "organization.ids.organization_id", "organization.name", @@ -133,6 +136,7 @@ var UpdateOrganizationRequestFieldPathsNested = []string{ "organization.created_at", "organization.deleted_at", "organization.description", + "organization.fanout_notifications", "organization.ids", "organization.ids.organization_id", "organization.name", diff --git a/pkg/ttnpb/organization.pb.setters.fm.go b/pkg/ttnpb/organization.pb.setters.fm.go index 5af19339aa..c8e6d17adb 100644 --- a/pkg/ttnpb/organization.pb.setters.fm.go +++ b/pkg/ttnpb/organization.pb.setters.fm.go @@ -147,6 +147,16 @@ func (dst *Organization) SetFields(src *Organization, paths ...string) error { dst.TechnicalContact = nil } } + case "fanout_notifications": + if len(subs) > 0 { + return fmt.Errorf("'fanout_notifications' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.FanoutNotifications = src.FanoutNotifications + } else { + var zero bool + dst.FanoutNotifications = zero + } default: return fmt.Errorf("invalid field: '%s'", name) diff --git a/pkg/ttnpb/organization.pb.validate.go b/pkg/ttnpb/organization.pb.validate.go index 64a95ca953..dae292d46a 100644 --- a/pkg/ttnpb/organization.pb.validate.go +++ b/pkg/ttnpb/organization.pb.validate.go @@ -203,6 +203,8 @@ func (m *Organization) ValidateFields(paths ...string) error { } } + case "fanout_notifications": + // no validation rules for FanoutNotifications default: return OrganizationValidationError{ field: name, diff --git a/pkg/ttnpb/organization_flags.pb.go b/pkg/ttnpb/organization_flags.pb.go index 1713812c51..844bb7863a 100644 --- a/pkg/ttnpb/organization_flags.pb.go +++ b/pkg/ttnpb/organization_flags.pb.go @@ -23,6 +23,7 @@ func AddSelectFlagsForOrganization(flags *pflag.FlagSet, prefix string, hidden b AddSelectFlagsForOrganizationOrUserIdentifiers(flags, flagsplugin.Prefix("administrative-contact", prefix), hidden) flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("technical-contact", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("technical-contact", prefix), true), flagsplugin.WithHidden(hidden))) AddSelectFlagsForOrganizationOrUserIdentifiers(flags, flagsplugin.Prefix("technical-contact", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("fanout-notifications", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("fanout-notifications", prefix), false), flagsplugin.WithHidden(hidden))) } // SelectFromFlags outputs the fieldmask paths forOrganization message from select flags. @@ -72,6 +73,11 @@ func PathsFromSelectFlagsForOrganization(flags *pflag.FlagSet, prefix string) (p } else { paths = append(paths, selectPaths...) } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("fanout_notifications", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("fanout_notifications", prefix)) + } return paths, nil } @@ -84,6 +90,7 @@ func AddSetFlagsForOrganization(flags *pflag.FlagSet, prefix string, hidden bool // FIXME: Skipping ContactInfo because repeated messages are currently not supported. AddSetFlagsForOrganizationOrUserIdentifiers(flags, flagsplugin.Prefix("administrative-contact", prefix), hidden) AddSetFlagsForOrganizationOrUserIdentifiers(flags, flagsplugin.Prefix("technical-contact", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("fanout-notifications", prefix), "", flagsplugin.WithHidden(hidden))) } // SetFromFlags sets the Organization message from flags. @@ -137,6 +144,12 @@ func (m *Organization) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths paths = append(paths, setPaths...) } } + if val, changed, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("fanout_notifications", prefix)); err != nil { + return nil, err + } else if changed { + m.FanoutNotifications = val + paths = append(paths, flagsplugin.Prefix("fanout_notifications", prefix)) + } return paths, nil } diff --git a/pkg/ttnpb/organization_json.pb.go b/pkg/ttnpb/organization_json.pb.go index e4332d3f89..39b510c403 100644 --- a/pkg/ttnpb/organization_json.pb.go +++ b/pkg/ttnpb/organization_json.pb.go @@ -97,6 +97,11 @@ func (x *Organization) MarshalProtoJSON(s *jsonplugin.MarshalState) { // NOTE: OrganizationOrUserIdentifiers does not seem to implement MarshalProtoJSON. golang.MarshalMessage(s, x.TechnicalContact) } + if x.FanoutNotifications || s.HasField("fanout_notifications") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("fanout_notifications") + s.WriteBool(x.FanoutNotifications) + } s.WriteObjectEnd() } @@ -211,6 +216,9 @@ func (x *Organization) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { var v OrganizationOrUserIdentifiers golang.UnmarshalMessage(s, &v) x.TechnicalContact = &v + case "fanout_notifications", "fanoutNotifications": + s.AddField("fanout_notifications") + x.FanoutNotifications = s.ReadBool() } }) } diff --git a/sdk/js/generated/api-definition.json b/sdk/js/generated/api-definition.json index 3078a28a77..10a5de84a3 100644 --- a/sdk/js/generated/api-definition.json +++ b/sdk/js/generated/api-definition.json @@ -6170,6 +6170,7 @@ "created_at", "deleted_at", "description", + "fanout_notifications", "ids", "ids.organization_id", "name", @@ -6212,6 +6213,7 @@ "created_at", "deleted_at", "description", + "fanout_notifications", "ids", "ids.organization_id", "name", @@ -6250,6 +6252,7 @@ "created_at", "deleted_at", "description", + "fanout_notifications", "ids", "ids.organization_id", "name", @@ -6841,6 +6844,7 @@ "created_at", "deleted_at", "description", + "fanout_notifications", "ids", "ids.organization_id", "name", diff --git a/sdk/js/generated/api.json b/sdk/js/generated/api.json index ecef384e9b..41cbb1b6b6 100644 --- a/sdk/js/generated/api.json +++ b/sdk/js/generated/api.json @@ -42042,6 +42042,18 @@ "isoneof": false, "oneofdecl": "", "defaultValue": "" + }, + { + "name": "fanout_notifications", + "description": "Determines if a notification will be sent to the collaborators. If false it, notifications will be sent only to the\nadministrative or technical contact.", + "label": "", + "type": "bool", + "longType": "bool", + "fullType": "bool", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" } ] }, From 6e0217da4ac0f522d1084073bb315e26ce1ad57d Mon Sep 17 00:00:00 2001 From: Nicholas Cristofaro Date: Mon, 11 Dec 2023 18:03:31 -0300 Subject: [PATCH 3/9] is: Add FanoutNotifications field to organization model --- .../bunstore/organization_store.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/pkg/identityserver/bunstore/organization_store.go b/pkg/identityserver/bunstore/organization_store.go index 3ef2ef0e74..03c88ae497 100644 --- a/pkg/identityserver/bunstore/organization_store.go +++ b/pkg/identityserver/bunstore/organization_store.go @@ -51,6 +51,8 @@ type Organization struct { TechnicalContactID *string `bun:"technical_contact_id,type:uuid"` TechnicalContact *Account `bun:"rel:belongs-to,join:technical_contact_id=id"` + + FanoutNotifications bool `bun:"fanout_notifications"` } // BeforeAppendModel is a hook that modifies the model on SELECT and UPDATE queries. @@ -71,8 +73,9 @@ func organizationToPB(m *Organization, fieldMask ...string) (*ttnpb.Organization UpdatedAt: timestamppb.New(m.UpdatedAt), DeletedAt: ttnpb.ProtoTime(m.DeletedAt), - Name: m.Name, - Description: m.Description, + Name: m.Name, + Description: m.Description, + FanoutNotifications: m.FanoutNotifications, } if len(m.Attributes) > 0 { @@ -137,8 +140,9 @@ func (s *organizationStore) CreateOrganization( Account: EmbeddedAccount{ UID: pb.GetIds().GetOrganizationId(), }, - Name: pb.Name, - Description: pb.Description, + Name: pb.Name, + Description: pb.Description, + FanoutNotifications: pb.FanoutNotifications, } if contact := pb.AdministrativeContact; contact != nil { @@ -229,7 +233,7 @@ func (*organizationStore) selectWithFields(q *bun.SelectQuery, fieldMask store.F return nil, fmt.Errorf("unknown field %q", f) case "ids", "created_at", "updated_at", "deleted_at": // Always selected. - case "name", "description": + case "name", "description", "fanout_notifications": // Proto name equals model name. columns = append(columns, f) case "attributes": @@ -441,6 +445,10 @@ func (s *organizationStore) updateOrganizationModel( //nolint:gocyclo model.TechnicalContactID = nil } columns = append(columns, "technical_contact_id") + + case "fanout_notifications": + model.FanoutNotifications = pb.FanoutNotifications + columns = append(columns, "fanout_notifications") } } From 2943d15440319129f978d82128afb384e14d3eb4 Mon Sep 17 00:00:00 2001 From: Nicholas Cristofaro Date: Mon, 11 Dec 2023 18:15:39 -0300 Subject: [PATCH 4/9] is: Add FanoutNotifications to UpdateOrganization test --- pkg/identityserver/storetest/organization_store.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/identityserver/storetest/organization_store.go b/pkg/identityserver/storetest/organization_store.go index c55044af21..dd90fb05f8 100644 --- a/pkg/identityserver/storetest/organization_store.go +++ b/pkg/identityserver/storetest/organization_store.go @@ -132,6 +132,7 @@ func (st *StoreTest) TestOrganizationStoreCRUD(t *T) { Attributes: updatedAttributes, AdministrativeContact: usr2.GetOrganizationOrUserIdentifiers(), TechnicalContact: usr1.GetOrganizationOrUserIdentifiers(), + FanoutNotifications: true, }, mask) if a.So(err, should.BeNil) && a.So(updated, should.NotBeNil) { a.So(updated.GetIds().GetOrganizationId(), should.Equal, "foo") @@ -140,6 +141,7 @@ func (st *StoreTest) TestOrganizationStoreCRUD(t *T) { a.So(updated.Attributes, should.Resemble, updatedAttributes) a.So(updated.AdministrativeContact, should.Resemble, usr2.GetOrganizationOrUserIdentifiers()) a.So(updated.TechnicalContact, should.Resemble, usr1.GetOrganizationOrUserIdentifiers()) + a.So(updated.FanoutNotifications, should.BeTrue) a.So(*ttnpb.StdTime(updated.CreatedAt), should.Equal, *ttnpb.StdTime(created.CreatedAt)) a.So(*ttnpb.StdTime(updated.UpdatedAt), should.HappenWithin, 5*time.Second, start) } From c6cb9545d3fc0a354167baa792a89c657bc58e94 Mon Sep 17 00:00:00 2001 From: Nicholas Cristofaro Date: Tue, 12 Dec 2023 12:54:51 -0300 Subject: [PATCH 5/9] is: Update notification registry --- pkg/identityserver/notification_registry.go | 48 +++++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/pkg/identityserver/notification_registry.go b/pkg/identityserver/notification_registry.go index 1b07034bda..dfb80959ad 100644 --- a/pkg/identityserver/notification_registry.go +++ b/pkg/identityserver/notification_registry.go @@ -78,6 +78,34 @@ func (is *IdentityServer) notifyInternal(ctx context.Context, req *ttnpb.CreateN var errNoReceiverUserIDs = errors.Define("no_receiver_user_ids", "no receiver users ids") +// getContactReceivers checks if the entityID to provide the appropriate receiverID. +// If is an user, returns the entityID. +// If is an organization, it checks if the fanout_notifications is enabled. If enabled returns the organizationID but +// otherwise it returns the organization's administrative or technical contact. +func (is *IdentityServer) getContactReceivers( + ctx context.Context, entityID *ttnpb.OrganizationOrUserIdentifiers, entityMask []string, +) (*ttnpb.OrganizationOrUserIdentifiers, error) { + if entityID.EntityType() != "organization" { + return entityID, nil + } + org, err := is.store.GetOrganization( + ctx, entityID.GetOrganizationIds(), append(entityMask, "fanout_notifications"), + ) + if err != nil { + return nil, err + } + if org.FanoutNotifications { + return entityID, nil + } + if contact := org.GetAdministrativeContact(); contact != nil { + return contact, nil + } + if contact := org.GetTechnicalContact(); contact != nil { + return contact, nil + } + return entityID, nil +} + func (is *IdentityServer) lookupNotificationReceivers(ctx context.Context, req *ttnpb.CreateNotificationRequest) ([]*ttnpb.UserIdentifiers, error) { var receiverIDs []*ttnpb.OrganizationOrUserIdentifiers err := is.store.Transact(ctx, func(ctx context.Context, st store.Store) error { @@ -120,11 +148,23 @@ func (is *IdentityServer) lookupNotificationReceivers(ctx context.Context, req * return err } if entity != nil { // NOTE: entity is nil for entities that don't support contacts. - if receiversContains(req.Receivers, ttnpb.NotificationReceiver_NOTIFICATION_RECEIVER_ADMINISTRATIVE_CONTACT) && entity.GetAdministrativeContact() != nil { - receiverIDs = append(receiverIDs, entity.GetAdministrativeContact()) + adminContact, err := is.getContactReceivers( + ctx, entity.GetAdministrativeContact(), []string{"administrative_contact"}, + ) + if err != nil { + return err + } + if adminContact != nil { + receiverIDs = append(receiverIDs, adminContact) + } + techContact, err := is.getContactReceivers( + ctx, entity.GetTechnicalContact(), []string{"technical_contact"}, + ) + if err != nil { + return err } - if receiversContains(req.Receivers, ttnpb.NotificationReceiver_NOTIFICATION_RECEIVER_TECHNICAL_CONTACT) && entity.GetTechnicalContact() != nil { - receiverIDs = append(receiverIDs, entity.GetTechnicalContact()) + if techContact != nil { + receiverIDs = append(receiverIDs, techContact) } } } From b2629d51a69bdc981c0899d7848b9306219351db Mon Sep 17 00:00:00 2001 From: Nicholas Cristofaro Date: Tue, 12 Dec 2023 12:55:15 -0300 Subject: [PATCH 6/9] is: Add organization fanout tests to notification registry --- .../notification_registry_test.go | 96 ++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/pkg/identityserver/notification_registry_test.go b/pkg/identityserver/notification_registry_test.go index 6aecddcfe2..f0ce0bc75a 100644 --- a/pkg/identityserver/notification_registry_test.go +++ b/pkg/identityserver/notification_registry_test.go @@ -15,6 +15,7 @@ package identityserver import ( + "fmt" "testing" "time" @@ -61,7 +62,7 @@ func TestNotificationRegistry(t *testing.T) { ttnpb.NotificationReceiver_NOTIFICATION_RECEIVER_ADMINISTRATIVE_CONTACT, ttnpb.NotificationReceiver_NOTIFICATION_RECEIVER_TECHNICAL_CONTACT, }, - }, is.WithClusterAuth()) + }, is.Component.WithClusterAuth()) if a.So(err, should.BeNil) && a.So(res, should.NotBeNil) { a.So(res.Id, should.NotBeZeroValue) } @@ -98,3 +99,96 @@ func TestNotificationRegistry(t *testing.T) { } }, withPrivateTestDatabase(p)) } + +// TestNotificationRegistryWithOrganizationFanout contains the test case for notifications that trigger the organization +// fanout, validating the expected behavior. More details below. +// +// Base conditions: +// - Three users, the owner and two collaborators. +// - Two organizations, one with fanout and another without. +// - Two applications, one for each organization. The organization is the owner and admin/tech contact. +// +// Expected behavior: +// - Create notification for app-1 (no fanout). Only the owner should receive the notification. +// - Create notification for app2-2 (has fanout). Both the owner and collaborators should receive the notification. +func TestNotificationRegistryWithOrganizationFanout(t *testing.T) { + t.Parallel() + p := &storetest.Population{} + + usr1 := p.NewUser() + usr1Key, _ := p.NewAPIKey(usr1.GetEntityIdentifiers(), ttnpb.Right_RIGHT_ALL) + usr1Creds := rpcCreds(usr1Key) + + usr2 := p.NewUser() + usr2Key, _ := p.NewAPIKey(usr2.GetEntityIdentifiers(), ttnpb.Right_RIGHT_ALL) + usr2Creds := rpcCreds(usr2Key) + usr3 := p.NewUser() + usr3Key, _ := p.NewAPIKey(usr3.GetEntityIdentifiers(), ttnpb.Right_RIGHT_ALL) + usr3Creds := rpcCreds(usr3Key) + + org1 := p.NewOrganization(usr1.GetOrganizationOrUserIdentifiers()) + org2 := p.NewOrganization(usr1.GetOrganizationOrUserIdentifiers()) + org2.FanoutNotifications = true + + // Register users as collaborators on both organizations. + for _, org := range []*ttnpb.Organization{org1, org2} { + org := org + for _, collab := range []*ttnpb.User{usr2, usr3} { + collab := collab + p.NewMembership( + collab.GetOrganizationOrUserIdentifiers(), + org.GetEntityIdentifiers(), + ttnpb.Right_RIGHT_ORGANIZATION_ALL, + ) + } + } + + // Sends notification to application's admin/tech contacts. + // Depending on the organization's fanout setting, the amount of receivers will vary. + app1 := p.NewApplication(org1.GetOrganizationOrUserIdentifiers()) + app2 := p.NewApplication(org2.GetOrganizationOrUserIdentifiers()) + + a, ctx := test.New(t) + testWithIdentityServer(t, func(is *IdentityServer, cc *grpc.ClientConn) { + svc := ttnpb.NewNotificationServiceClient(cc) + + for _, entityID := range []*ttnpb.EntityIdentifiers{ + app1.GetIds().GetEntityIdentifiers(), + app2.GetIds().GetEntityIdentifiers(), + } { + entityID := entityID + res, err := svc.Create(ctx, &ttnpb.CreateNotificationRequest{ + EntityIds: entityID, + NotificationType: "test_notification", + Receivers: []ttnpb.NotificationReceiver{ + ttnpb.NotificationReceiver_NOTIFICATION_RECEIVER_ADMINISTRATIVE_CONTACT, + ttnpb.NotificationReceiver_NOTIFICATION_RECEIVER_TECHNICAL_CONTACT, + }, + }, is.Component.WithClusterAuth()) + if a.So(err, should.BeNil) && a.So(res, should.NotBeNil) { + a.So(res.Id, should.NotBeZeroValue) + } + } + + // Validates the amount of notifications received by each user. + for _, tt := range []struct { + userID *ttnpb.UserIdentifiers + notificationAmount int + creds grpc.CallOption + }{ + {userID: usr1.GetIds(), notificationAmount: 2, creds: usr1Creds}, + {userID: usr2.GetIds(), notificationAmount: 1, creds: usr2Creds}, + {userID: usr3.GetIds(), notificationAmount: 1, creds: usr3Creds}, + } { + tt := tt + ttName := fmt.Sprintf("Expect %s to have %d notifications", tt.userID.GetUserId(), tt.notificationAmount) + t.Run(ttName, func(t *testing.T) { // nolint:paralleltest + a, ctx := test.New(t) + list, err := svc.List(ctx, &ttnpb.ListNotificationsRequest{ReceiverIds: tt.userID}, tt.creds) + a.So(err, should.BeNil) + a.So(list, should.NotBeNil) + a.So(list.Notifications, should.HaveLength, tt.notificationAmount) + }) + } + }, withPrivateTestDatabase(p)) +} From 01538d56e1398f3c5a59d11fe24960954642ee60 Mon Sep 17 00:00:00 2001 From: Nicholas Cristofaro Date: Tue, 9 Jan 2024 14:13:13 -0300 Subject: [PATCH 7/9] js: Add fan-out checkbox to organization general settings form --- .../console/containers/organization-form/form.js | 15 +++++++++++++++ pkg/webui/console/views/organization/index.js | 5 ++++- pkg/webui/lib/constants/tooltip-ids.js | 1 + pkg/webui/lib/shared-messages.js | 4 ++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/pkg/webui/console/containers/organization-form/form.js b/pkg/webui/console/containers/organization-form/form.js index c5aede2919..3fe84eec3c 100644 --- a/pkg/webui/console/containers/organization-form/form.js +++ b/pkg/webui/console/containers/organization-form/form.js @@ -20,6 +20,7 @@ import Form from '@ttn-lw/components/form' import Input from '@ttn-lw/components/input' import SubmitBar from '@ttn-lw/components/submit-bar' import SubmitButton from '@ttn-lw/components/submit-button' +import Checkbox from '@ttn-lw/components/checkbox' import CollaboratorSelect from '@ttn-lw/containers/collaborator-select' import { decodeContact, encodeContact } from '@ttn-lw/containers/collaborator-select/util' @@ -29,6 +30,7 @@ import Message from '@ttn-lw/lib/components/message' import Yup from '@ttn-lw/lib/yup' import PropTypes from '@ttn-lw/lib/prop-types' import sharedMessages from '@ttn-lw/lib/shared-messages' +import tooltipIds from '@ttn-lw/lib/constants/tooltip-ids' import { id as organizationIdRegexp } from '@ttn-lw/lib/regexp' import contactSchema from '@ttn-lw/lib/shared-schemas' @@ -147,6 +149,19 @@ const OrganizationForm = props => { component="p" className="mt-cs-xs tc-subtle-gray" /> + + )} diff --git a/pkg/webui/console/views/organization/index.js b/pkg/webui/console/views/organization/index.js index 3ae3b0a883..3e93bab8bf 100644 --- a/pkg/webui/console/views/organization/index.js +++ b/pkg/webui/console/views/organization/index.js @@ -66,7 +66,10 @@ const Organization = () => { diff --git a/pkg/webui/lib/constants/tooltip-ids.js b/pkg/webui/lib/constants/tooltip-ids.js index 20efe2944a..29d785ef35 100644 --- a/pkg/webui/lib/constants/tooltip-ids.js +++ b/pkg/webui/lib/constants/tooltip-ids.js @@ -46,6 +46,7 @@ export default Object.freeze({ GATEWAY_ATTRIBUTES: 'gateway-attributes', GATEWAY_DESCRIPTION: 'gateway-description', GATEWAY_EUI: 'gateway-eui', + GATEWAY_FANOUT_NOTIFICATIONS: 'gateway-fanout-notifications', GATEWAY_ID: 'gateway-id', GATEWAY_LOCATION_PUBLIC: 'gateway-location-public', GATEWAY_NAME: 'gateway-name', diff --git a/pkg/webui/lib/shared-messages.js b/pkg/webui/lib/shared-messages.js index b8578d3e27..015e15ab5e 100644 --- a/pkg/webui/lib/shared-messages.js +++ b/pkg/webui/lib/shared-messages.js @@ -253,6 +253,10 @@ export default defineMessages({ gatewayDescPlaceholder: 'Description for my new gateway', gatewayDescription: 'Gateway description', gatewayEUI: 'Gateway EUI', + gatewayFanoutNotificationsTitle: 'Fan-out notifications', + gatewayFanoutNotificationsLabel: 'Enable fan-out notifications', + gatewayFanoutNotificationsDescription: + 'Notifications sent to this organization will be propagated to all collaborators instead of the respective administrative or technical contact.', gatewayID: 'Gateway ID', gatewayIdPlaceholder: 'my-new-gateway', gatewayLocation: 'Gateway location', From 09f04eea3c9c0cfb950fda1c943ddc61e697a97e Mon Sep 17 00:00:00 2001 From: Nicholas Cristofaro Date: Tue, 16 Jan 2024 16:40:11 -0300 Subject: [PATCH 8/9] js: Add translations --- pkg/webui/locales/en.json | 3 +++ pkg/webui/locales/ja.json | 3 +++ 2 files changed, 6 insertions(+) diff --git a/pkg/webui/locales/en.json b/pkg/webui/locales/en.json index 334ecdaf14..3b534171a9 100644 --- a/pkg/webui/locales/en.json +++ b/pkg/webui/locales/en.json @@ -1191,6 +1191,9 @@ "lib.shared-messages.gatewayDescPlaceholder": "Description for my new gateway", "lib.shared-messages.gatewayDescription": "Gateway description", "lib.shared-messages.gatewayEUI": "Gateway EUI", + "lib.shared-messages.gatewayFanoutNotificationsTitle": "Fan-out notifications", + "lib.shared-messages.gatewayFanoutNotificationsLabel": "Enable fan-out notifications", + "lib.shared-messages.gatewayFanoutNotificationsDescription": "Notifications sent to this organization will be propagated to all collaborators instead of the respective administrative or technical contact.", "lib.shared-messages.gatewayID": "Gateway ID", "lib.shared-messages.gatewayIdPlaceholder": "my-new-gateway", "lib.shared-messages.gatewayLocation": "Gateway location", diff --git a/pkg/webui/locales/ja.json b/pkg/webui/locales/ja.json index 5dd59b2b5b..e4d6d76638 100644 --- a/pkg/webui/locales/ja.json +++ b/pkg/webui/locales/ja.json @@ -1191,6 +1191,9 @@ "lib.shared-messages.gatewayDescPlaceholder": "新しいゲートウェイの説明", "lib.shared-messages.gatewayDescription": "ゲートウェイの説明", "lib.shared-messages.gatewayEUI": "ゲートウェイEUI", + "lib.shared-messages.gatewayFanoutNotificationsTitle": "", + "lib.shared-messages.gatewayFanoutNotificationsLabel": "", + "lib.shared-messages.gatewayFanoutNotificationsDescription": "", "lib.shared-messages.gatewayID": "ゲートウェイID", "lib.shared-messages.gatewayIdPlaceholder": "my-new-gateway", "lib.shared-messages.gatewayLocation": "ゲートウェイの場所", From 4b10010cb62a20e5ede096c61ad4fff4230f8370 Mon Sep 17 00:00:00 2001 From: Nicholas Cristofaro Date: Tue, 12 Dec 2023 16:52:03 -0300 Subject: [PATCH 9/9] dev: Update CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8555846bce..aa8969da63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,9 @@ For details about compatibility between different releases, see the **Commitment - This enables CUPS-enabled gateways to change their LNS before the periodic CUPS lookup occurs. - The LoRa Basics Station discovery endpoint now verifies the authorization credentials of the caller. - This enables the gateways to migrate to another instance gracefully while using CUPS. +- Organizations can now opt out from sending administrative and technical notifications to its members. + - New organizations do not send administrative and technical notifications to its members by default. + - To alter the behavior update the organization's `fanout_notifications` field. ### Fixed