From 99a44111611e352bc818175b26109333abf94c27 Mon Sep 17 00:00:00 2001 From: Nicholas Cristofaro Date: Thu, 4 Jan 2024 14:11:55 +0000 Subject: [PATCH 1/5] is: Add user console preferences migration --- .../20240103000001_console_preferences.down.sql | 15 +++++++++++++++ .../20240103000001_console_preferences.up.sql | 16 ++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 pkg/identityserver/store/migrations/20240103000001_console_preferences.down.sql create mode 100644 pkg/identityserver/store/migrations/20240103000001_console_preferences.up.sql diff --git a/pkg/identityserver/store/migrations/20240103000001_console_preferences.down.sql b/pkg/identityserver/store/migrations/20240103000001_console_preferences.down.sql new file mode 100644 index 0000000000..fd71d4a256 --- /dev/null +++ b/pkg/identityserver/store/migrations/20240103000001_console_preferences.down.sql @@ -0,0 +1,15 @@ +ALTER TABLE users DROP COLUMN IF EXISTS console_preferences CASCADE; + +--bun:split +CREATE OR REPLACE VIEW user_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, + usr.* +FROM + accounts acc + JOIN users usr ON usr.id = acc.account_id + AND acc.account_type = 'user'; diff --git a/pkg/identityserver/store/migrations/20240103000001_console_preferences.up.sql b/pkg/identityserver/store/migrations/20240103000001_console_preferences.up.sql new file mode 100644 index 0000000000..cbf83c5f2c --- /dev/null +++ b/pkg/identityserver/store/migrations/20240103000001_console_preferences.up.sql @@ -0,0 +1,16 @@ +ALTER TABLE users +ADD COLUMN IF NOT EXISTS console_preferences bytea; + +--bun:split +CREATE OR REPLACE VIEW user_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, + usr.* +FROM + accounts acc + JOIN users usr ON usr.id = acc.account_id + AND acc.account_type = 'user'; From 73cfce97b56d3c0a8f2b194749472677e81ddfea Mon Sep 17 00:00:00 2001 From: Nicholas Cristofaro Date: Thu, 4 Jan 2024 14:14:30 +0000 Subject: [PATCH 2/5] api: Add UserConsolePreferences proto message definition --- api/buf.yaml | 1 + api/ttn/lorawan/v3/api.md | 75 ++ api/ttn/lorawan/v3/api.swagger.json | 99 ++ api/ttn/lorawan/v3/user.proto | 150 ++- pkg/ttnpb/user.pb.go | 1638 +++++++++++++++++--------- pkg/ttnpb/user.pb.paths.fm.go | 124 ++ pkg/ttnpb/user.pb.setters.fm.go | 259 ++++ pkg/ttnpb/user.pb.validate.go | 448 +++++++ pkg/ttnpb/user_flags.pb.go | 78 ++ pkg/ttnpb/user_json.pb.go | 274 +++++ sdk/js/generated/api-definition.json | 76 ++ sdk/js/generated/api.json | 443 ++++++- 12 files changed, 3124 insertions(+), 541 deletions(-) diff --git a/api/buf.yaml b/api/buf.yaml index 17febb211c..953009fc8a 100644 --- a/api/buf.yaml +++ b/api/buf.yaml @@ -48,6 +48,7 @@ lint: - ttn/lorawan/v3/metadata.proto - ttn/lorawan/v3/notification_service.proto - ttn/lorawan/v3/rights.proto + - ttn/lorawan/v3/user.proto FIELD_LOWER_SNAKE_CASE: - ttn/lorawan/v3/applicationserver_integrations_alcsync.proto FILE_LOWER_SNAKE_CASE: diff --git a/api/ttn/lorawan/v3/api.md b/api/ttn/lorawan/v3/api.md index b0955178a5..6b04408ab0 100644 --- a/api/ttn/lorawan/v3/api.md +++ b/api/ttn/lorawan/v3/api.md @@ -769,10 +769,15 @@ - [Message `UpdateUserRequest`](#ttn.lorawan.v3.UpdateUserRequest) - [Message `User`](#ttn.lorawan.v3.User) - [Message `User.AttributesEntry`](#ttn.lorawan.v3.User.AttributesEntry) + - [Message `UserConsolePreferences`](#ttn.lorawan.v3.UserConsolePreferences) + - [Message `UserConsolePreferences.DashboardLayouts`](#ttn.lorawan.v3.UserConsolePreferences.DashboardLayouts) + - [Message `UserConsolePreferences.SortBy`](#ttn.lorawan.v3.UserConsolePreferences.SortBy) - [Message `UserSession`](#ttn.lorawan.v3.UserSession) - [Message `UserSessionIdentifiers`](#ttn.lorawan.v3.UserSessionIdentifiers) - [Message `UserSessions`](#ttn.lorawan.v3.UserSessions) - [Message `Users`](#ttn.lorawan.v3.Users) + - [Enum `ConsoleTheme`](#ttn.lorawan.v3.ConsoleTheme) + - [Enum `DashboardLayout`](#ttn.lorawan.v3.DashboardLayout) - [File `ttn/lorawan/v3/user_services.proto`](#ttn/lorawan/v3/user_services.proto) - [Service `UserAccess`](#ttn.lorawan.v3.UserAccess) - [Service `UserInvitationRegistry`](#ttn.lorawan.v3.UserInvitationRegistry) @@ -10835,6 +10840,7 @@ User is the message that defines a user on the network. | `temporary_password_created_at` | [`google.protobuf.Timestamp`](#google.protobuf.Timestamp) | | | | `temporary_password_expires_at` | [`google.protobuf.Timestamp`](#google.protobuf.Timestamp) | | | | `profile_picture` | [`Picture`](#ttn.lorawan.v3.Picture) | | A profile picture for the user. This information is public and can be seen by any authenticated user in the network. | +| `console_preferences` | [`UserConsolePreferences`](#ttn.lorawan.v3.UserConsolePreferences) | | Console preferences contains the user's preferences regarding the behavior of the Console. | #### Field Rules @@ -10858,6 +10864,55 @@ User is the message that defines a user on the network. | `key` | [`string`](#string) | | | | `value` | [`string`](#string) | | | +### Message `UserConsolePreferences` + +UserConsolePreferences is the message that defines the user preferences for the Console. + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `console_theme` | [`ConsoleTheme`](#ttn.lorawan.v3.ConsoleTheme) | | | +| `dashboard_layouts` | [`UserConsolePreferences.DashboardLayouts`](#ttn.lorawan.v3.UserConsolePreferences.DashboardLayouts) | | | +| `sort_by` | [`UserConsolePreferences.SortBy`](#ttn.lorawan.v3.UserConsolePreferences.SortBy) | | | + +### Message `UserConsolePreferences.DashboardLayouts` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `api_key` | [`DashboardLayout`](#ttn.lorawan.v3.DashboardLayout) | | | +| `application` | [`DashboardLayout`](#ttn.lorawan.v3.DashboardLayout) | | | +| `collaborator` | [`DashboardLayout`](#ttn.lorawan.v3.DashboardLayout) | | | +| `end_device` | [`DashboardLayout`](#ttn.lorawan.v3.DashboardLayout) | | | +| `gateway` | [`DashboardLayout`](#ttn.lorawan.v3.DashboardLayout) | | | +| `organization` | [`DashboardLayout`](#ttn.lorawan.v3.DashboardLayout) | | | +| `overview` | [`DashboardLayout`](#ttn.lorawan.v3.DashboardLayout) | | | +| `user` | [`DashboardLayout`](#ttn.lorawan.v3.DashboardLayout) | | | + +### Message `UserConsolePreferences.SortBy` + +SortBy defines the field to which the Console will sort the display of entities. + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `api_key` | [`string`](#string) | | | +| `application` | [`string`](#string) | | | +| `collaborator` | [`string`](#string) | | | +| `end_device` | [`string`](#string) | | | +| `gateway` | [`string`](#string) | | | +| `organization` | [`string`](#string) | | | +| `user` | [`string`](#string) | | | + +#### Field Rules + +| Field | Validations | +| ----- | ----------- | +| `api_key` |

`string.in`: `[ api_key_id -api_key_id name -name created_at -created_at expires_at -expires_at]`

| +| `application` |

`string.in`: `[ application_id -application_id name -name created_at -created_at]`

| +| `collaborator` |

`string.in`: `[ id -id rights -rights]`

| +| `end_device` |

`string.in`: `[ device_id -device_id join_eui -join_eui dev_eui -dev_eui name -name description -description created_at -created_at last_seen_at -last_seen_at]`

| +| `gateway` |

`string.in`: `[ gateway_id -gateway_id gateway_eui -gateway_eui name -name created_at -created_at]`

| +| `organization` |

`string.in`: `[ organization_id -organization_id name -name created_at -created_at]`

| +| `user` |

`string.in`: `[ user_id -user_id name -name primary_email_address -primary_email_address state -state admin -admin created_at -created_at]`

| + ### Message `UserSession` | Field | Type | Label | Description | @@ -10902,6 +10957,26 @@ User is the message that defines a user on the network. | ----- | ---- | ----- | ----------- | | `users` | [`User`](#ttn.lorawan.v3.User) | repeated | | +### Enum `ConsoleTheme` + +ConsoleTheme is the theme of the Console. + +| Name | Number | Description | +| ---- | ------ | ----------- | +| `CONSOLE_THEME_SYSTEM` | 0 | The user prefers the system mode. | +| `CONSOLE_THEME_LIGHT` | 1 | The user prefers the light mode. | +| `CONSOLE_THEME_DARK` | 2 | The user prefers the dark mode. | + +### Enum `DashboardLayout` + +DashboardLayout is a set of possible layout values to be used in the Console. + +| Name | Number | Description | +| ---- | ------ | ----------- | +| `DASHBOARD_LAYOUT_TABLE` | 0 | | +| `DASHBOARD_LAYOUT_LIST` | 1 | | +| `DASHBOARD_LAYOUT_GRID` | 2 | | + ## File `ttn/lorawan/v3/user_services.proto` ### Service `UserAccess` diff --git a/api/ttn/lorawan/v3/api.swagger.json b/api/ttn/lorawan/v3/api.swagger.json index 6f44936803..61422d00d2 100644 --- a/api/ttn/lorawan/v3/api.swagger.json +++ b/api/ttn/lorawan/v3/api.swagger.json @@ -16565,6 +16565,62 @@ "UplinkMessageRxMetadataRelayMetadata": { "type": "object" }, + "UserConsolePreferencesDashboardLayouts": { + "type": "object", + "properties": { + "api_key": { + "$ref": "#/definitions/v3DashboardLayout" + }, + "application": { + "$ref": "#/definitions/v3DashboardLayout" + }, + "collaborator": { + "$ref": "#/definitions/v3DashboardLayout" + }, + "end_device": { + "$ref": "#/definitions/v3DashboardLayout" + }, + "gateway": { + "$ref": "#/definitions/v3DashboardLayout" + }, + "organization": { + "$ref": "#/definitions/v3DashboardLayout" + }, + "overview": { + "$ref": "#/definitions/v3DashboardLayout" + }, + "user": { + "$ref": "#/definitions/v3DashboardLayout" + } + } + }, + "UserConsolePreferencesSortBy": { + "type": "object", + "properties": { + "api_key": { + "type": "string" + }, + "application": { + "type": "string" + }, + "collaborator": { + "type": "string" + }, + "end_device": { + "type": "string" + }, + "gateway": { + "type": "string" + }, + "organization": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "description": "SortBy defines the field to which the Console will sort the display of entities." + }, "UserRegistrationAdminApproval": { "type": "object", "properties": { @@ -19859,6 +19915,16 @@ } } }, + "v3ConsoleTheme": { + "type": "string", + "enum": [ + "CONSOLE_THEME_SYSTEM", + "CONSOLE_THEME_LIGHT", + "CONSOLE_THEME_DARK" + ], + "default": "CONSOLE_THEME_SYSTEM", + "description": "ConsoleTheme is the theme of the Console.\n\n - CONSOLE_THEME_SYSTEM: The user prefers the system mode.\n - CONSOLE_THEME_LIGHT: The user prefers the light mode.\n - CONSOLE_THEME_DARK: The user prefers the dark mode." + }, "v3ContactInfo": { "type": "object", "properties": { @@ -20015,6 +20081,16 @@ } } }, + "v3DashboardLayout": { + "type": "string", + "enum": [ + "DASHBOARD_LAYOUT_TABLE", + "DASHBOARD_LAYOUT_LIST", + "DASHBOARD_LAYOUT_GRID" + ], + "default": "DASHBOARD_LAYOUT_TABLE", + "description": "DashboardLayout is a set of possible layout values to be used in the Console." + }, "v3DataRate": { "type": "object", "properties": { @@ -26092,6 +26168,10 @@ "profile_picture": { "$ref": "#/definitions/v3Picture", "description": "A profile picture for the user.\nThis information is public and can be seen by any authenticated user in the network." + }, + "console_preferences": { + "$ref": "#/definitions/v3UserConsolePreferences", + "description": "Console preferences contains the user's preferences regarding the behavior of the Console." } }, "description": "User is the message that defines a user on the network." @@ -26173,6 +26253,21 @@ } } }, + "v3UserConsolePreferences": { + "type": "object", + "properties": { + "console_theme": { + "$ref": "#/definitions/v3ConsoleTheme" + }, + "dashboard_layouts": { + "$ref": "#/definitions/UserConsolePreferencesDashboardLayouts" + }, + "sort_by": { + "$ref": "#/definitions/UserConsolePreferencesSortBy" + } + }, + "description": "UserConsolePreferences is the message that defines the user preferences for the Console." + }, "v3UserIdentifiers": { "type": "object", "properties": { @@ -26288,6 +26383,10 @@ "profile_picture": { "$ref": "#/definitions/v3Picture", "description": "A profile picture for the user.\nThis information is public and can be seen by any authenticated user in the network." + }, + "console_preferences": { + "$ref": "#/definitions/v3UserConsolePreferences", + "description": "Console preferences contains the user's preferences regarding the behavior of the Console." } }, "description": "User is the message that defines a user on the network." diff --git a/api/ttn/lorawan/v3/user.proto b/api/ttn/lorawan/v3/user.proto index b45946e6cc..15763529e3 100644 --- a/api/ttn/lorawan/v3/user.proto +++ b/api/ttn/lorawan/v3/user.proto @@ -19,6 +19,7 @@ package ttn.lorawan.v3; import "google/protobuf/field_mask.proto"; import "google/protobuf/timestamp.proto"; import "thethings/flags/annotations.proto"; +import "thethings/json/annotations.proto"; import "ttn/lorawan/v3/contact_info.proto"; import "ttn/lorawan/v3/enums.proto"; import "ttn/lorawan/v3/identifiers.proto"; @@ -28,6 +29,150 @@ import "validate/validate.proto"; option go_package = "go.thethings.network/lorawan-stack/v3/pkg/ttnpb"; +// ConsoleTheme is the theme of the Console. +enum ConsoleTheme { + option (thethings.json.enum) = { + marshal_as_string: true, + prefix: "CONSOLE_THEME" + }; + // The user prefers the system mode. + CONSOLE_THEME_SYSTEM = 0; + // The user prefers the light mode. + CONSOLE_THEME_LIGHT = 1; + // The user prefers the dark mode. + CONSOLE_THEME_DARK = 2; +} + +// DashboardLayout is a set of possible layout values to be used in the Console. +enum DashboardLayout { + option (thethings.json.enum) = { + marshal_as_string: true, + prefix: "DASHBOARD_LAYOUT" + }; + DASHBOARD_LAYOUT_TABLE = 0; + DASHBOARD_LAYOUT_LIST = 1; + DASHBOARD_LAYOUT_GRID = 2; +} + +// UserConsolePreferences is the message that defines the user preferences for the Console. +message UserConsolePreferences { + option (thethings.flags.message) = { + select: true, + set: true + }; + ConsoleTheme console_theme = 1; + + message DashboardLayouts { + DashboardLayout api_key = 1; + DashboardLayout application = 2; + DashboardLayout collaborator = 3; + DashboardLayout end_device = 4; + DashboardLayout gateway = 5; + DashboardLayout organization = 6; + DashboardLayout overview = 7; + DashboardLayout user = 8; + } + DashboardLayouts dashboard_layouts = 2; + + // SortBy defines the field to which the Console will sort the display of entities. + message SortBy { + string api_key = 1 [(validate.rules).string = { + in: [ + "", + "api_key_id", + "-api_key_id", + "name", + "-name", + "created_at", + "-created_at", + "expires_at", + "-expires_at" + ] + }]; + string application = 2 [(validate.rules).string = { + in: [ + "", + "application_id", + "-application_id", + "name", + "-name", + "created_at", + "-created_at" + ] + }]; + string collaborator = 3 [(validate.rules).string = { + in: [ + "", + "id", + "-id", + "rights", + "-rights" + ] + }]; + string end_device = 4 [(validate.rules).string = { + in: [ + "", + "device_id", + "-device_id", + "join_eui", + "-join_eui", + "dev_eui", + "-dev_eui", + "name", + "-name", + "description", + "-description", + "created_at", + "-created_at", + "last_seen_at", + "-last_seen_at" + ] + }]; + string gateway = 5 [(validate.rules).string = { + in: [ + "", + "gateway_id", + "-gateway_id", + "gateway_eui", + "-gateway_eui", + "name", + "-name", + "created_at", + "-created_at" + ] + }]; + string organization = 6 [(validate.rules).string = { + in: [ + "", + "organization_id", + "-organization_id", + "name", + "-name", + "created_at", + "-created_at" + ] + }]; + string user = 7 [(validate.rules).string = { + in: [ + "", + "user_id", + "-user_id", + "name", + "-name", + "primary_email_address", + "-primary_email_address", + "state", + "-state", + "admin", + "-admin", + "created_at", + "-created_at" + ] + }]; + } + SortBy sort_by = 3; +} + // User is the message that defines a user on the network. message User { option (thethings.flags.message) = { @@ -140,7 +285,10 @@ message User { reserved 24; reserved "organization_limit"; - // next: 25 + // Console preferences contains the user's preferences regarding the behavior of the Console. + UserConsolePreferences console_preferences = 25; + + // next: 26 } message Users { diff --git a/pkg/ttnpb/user.pb.go b/pkg/ttnpb/user.pb.go index b3d074f1ef..7b1693c7b9 100644 --- a/pkg/ttnpb/user.pb.go +++ b/pkg/ttnpb/user.pb.go @@ -22,6 +22,7 @@ package ttnpb import ( _ "github.com/TheThingsIndustries/protoc-gen-go-flags/annotations" + _ "github.com/TheThingsIndustries/protoc-gen-go-json/annotations" _ "github.com/envoyproxy/protoc-gen-validate/validate" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" @@ -38,6 +39,173 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// ConsoleTheme is the theme of the Console. +type ConsoleTheme int32 + +const ( + // The user prefers the system mode. + ConsoleTheme_CONSOLE_THEME_SYSTEM ConsoleTheme = 0 + // The user prefers the light mode. + ConsoleTheme_CONSOLE_THEME_LIGHT ConsoleTheme = 1 + // The user prefers the dark mode. + ConsoleTheme_CONSOLE_THEME_DARK ConsoleTheme = 2 +) + +// Enum value maps for ConsoleTheme. +var ( + ConsoleTheme_name = map[int32]string{ + 0: "CONSOLE_THEME_SYSTEM", + 1: "CONSOLE_THEME_LIGHT", + 2: "CONSOLE_THEME_DARK", + } + ConsoleTheme_value = map[string]int32{ + "CONSOLE_THEME_SYSTEM": 0, + "CONSOLE_THEME_LIGHT": 1, + "CONSOLE_THEME_DARK": 2, + } +) + +func (x ConsoleTheme) Enum() *ConsoleTheme { + p := new(ConsoleTheme) + *p = x + return p +} + +func (x ConsoleTheme) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ConsoleTheme) Descriptor() protoreflect.EnumDescriptor { + return file_ttn_lorawan_v3_user_proto_enumTypes[0].Descriptor() +} + +func (ConsoleTheme) Type() protoreflect.EnumType { + return &file_ttn_lorawan_v3_user_proto_enumTypes[0] +} + +func (x ConsoleTheme) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ConsoleTheme.Descriptor instead. +func (ConsoleTheme) EnumDescriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{0} +} + +// DashboardLayout is a set of possible layout values to be used in the Console. +type DashboardLayout int32 + +const ( + DashboardLayout_DASHBOARD_LAYOUT_TABLE DashboardLayout = 0 + DashboardLayout_DASHBOARD_LAYOUT_LIST DashboardLayout = 1 + DashboardLayout_DASHBOARD_LAYOUT_GRID DashboardLayout = 2 +) + +// Enum value maps for DashboardLayout. +var ( + DashboardLayout_name = map[int32]string{ + 0: "DASHBOARD_LAYOUT_TABLE", + 1: "DASHBOARD_LAYOUT_LIST", + 2: "DASHBOARD_LAYOUT_GRID", + } + DashboardLayout_value = map[string]int32{ + "DASHBOARD_LAYOUT_TABLE": 0, + "DASHBOARD_LAYOUT_LIST": 1, + "DASHBOARD_LAYOUT_GRID": 2, + } +) + +func (x DashboardLayout) Enum() *DashboardLayout { + p := new(DashboardLayout) + *p = x + return p +} + +func (x DashboardLayout) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (DashboardLayout) Descriptor() protoreflect.EnumDescriptor { + return file_ttn_lorawan_v3_user_proto_enumTypes[1].Descriptor() +} + +func (DashboardLayout) Type() protoreflect.EnumType { + return &file_ttn_lorawan_v3_user_proto_enumTypes[1] +} + +func (x DashboardLayout) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use DashboardLayout.Descriptor instead. +func (DashboardLayout) EnumDescriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{1} +} + +// UserConsolePreferences is the message that defines the user preferences for the Console. +type UserConsolePreferences struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ConsoleTheme ConsoleTheme `protobuf:"varint,1,opt,name=console_theme,json=consoleTheme,proto3,enum=ttn.lorawan.v3.ConsoleTheme" json:"console_theme,omitempty"` + DashboardLayouts *UserConsolePreferences_DashboardLayouts `protobuf:"bytes,2,opt,name=dashboard_layouts,json=dashboardLayouts,proto3" json:"dashboard_layouts,omitempty"` + SortBy *UserConsolePreferences_SortBy `protobuf:"bytes,3,opt,name=sort_by,json=sortBy,proto3" json:"sort_by,omitempty"` +} + +func (x *UserConsolePreferences) Reset() { + *x = UserConsolePreferences{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserConsolePreferences) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserConsolePreferences) ProtoMessage() {} + +func (x *UserConsolePreferences) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserConsolePreferences.ProtoReflect.Descriptor instead. +func (*UserConsolePreferences) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{0} +} + +func (x *UserConsolePreferences) GetConsoleTheme() ConsoleTheme { + if x != nil { + return x.ConsoleTheme + } + return ConsoleTheme_CONSOLE_THEME_SYSTEM +} + +func (x *UserConsolePreferences) GetDashboardLayouts() *UserConsolePreferences_DashboardLayouts { + if x != nil { + return x.DashboardLayouts + } + return nil +} + +func (x *UserConsolePreferences) GetSortBy() *UserConsolePreferences_SortBy { + if x != nil { + return x.SortBy + } + return nil +} + // User is the message that defines a user on the network. type User struct { state protoimpl.MessageState @@ -95,12 +263,14 @@ type User struct { // A profile picture for the user. // This information is public and can be seen by any authenticated user in the network. ProfilePicture *Picture `protobuf:"bytes,18,opt,name=profile_picture,json=profilePicture,proto3" json:"profile_picture,omitempty"` + // Console preferences contains the user's preferences regarding the behavior of the Console. + ConsolePreferences *UserConsolePreferences `protobuf:"bytes,25,opt,name=console_preferences,json=consolePreferences,proto3" json:"console_preferences,omitempty"` } func (x *User) Reset() { *x = User{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[0] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -113,7 +283,7 @@ func (x *User) String() string { func (*User) ProtoMessage() {} func (x *User) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[0] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -126,7 +296,7 @@ func (x *User) ProtoReflect() protoreflect.Message { // Deprecated: Use User.ProtoReflect.Descriptor instead. func (*User) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{0} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{1} } func (x *User) GetIds() *UserIdentifiers { @@ -270,6 +440,13 @@ func (x *User) GetProfilePicture() *Picture { return nil } +func (x *User) GetConsolePreferences() *UserConsolePreferences { + if x != nil { + return x.ConsolePreferences + } + return nil +} + type Users struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -281,7 +458,7 @@ type Users struct { func (x *Users) Reset() { *x = Users{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[1] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -294,7 +471,7 @@ func (x *Users) String() string { func (*Users) ProtoMessage() {} func (x *Users) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[1] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -307,7 +484,7 @@ func (x *Users) ProtoReflect() protoreflect.Message { // Deprecated: Use Users.ProtoReflect.Descriptor instead. func (*Users) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{1} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{2} } func (x *Users) GetUsers() []*User { @@ -330,7 +507,7 @@ type GetUserRequest struct { func (x *GetUserRequest) Reset() { *x = GetUserRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[2] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -343,7 +520,7 @@ func (x *GetUserRequest) String() string { func (*GetUserRequest) ProtoMessage() {} func (x *GetUserRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[2] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -356,7 +533,7 @@ func (x *GetUserRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetUserRequest.ProtoReflect.Descriptor instead. func (*GetUserRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{2} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{3} } func (x *GetUserRequest) GetUserIds() *UserIdentifiers { @@ -394,7 +571,7 @@ type ListUsersRequest struct { func (x *ListUsersRequest) Reset() { *x = ListUsersRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[3] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -407,7 +584,7 @@ func (x *ListUsersRequest) String() string { func (*ListUsersRequest) ProtoMessage() {} func (x *ListUsersRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[3] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -420,7 +597,7 @@ func (x *ListUsersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListUsersRequest.ProtoReflect.Descriptor instead. func (*ListUsersRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{3} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{4} } func (x *ListUsersRequest) GetFieldMask() *fieldmaskpb.FieldMask { @@ -471,7 +648,7 @@ type CreateUserRequest struct { func (x *CreateUserRequest) Reset() { *x = CreateUserRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[4] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -484,7 +661,7 @@ func (x *CreateUserRequest) String() string { func (*CreateUserRequest) ProtoMessage() {} func (x *CreateUserRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[4] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -497,7 +674,7 @@ func (x *CreateUserRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateUserRequest.ProtoReflect.Descriptor instead. func (*CreateUserRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{4} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{5} } func (x *CreateUserRequest) GetUser() *User { @@ -527,7 +704,7 @@ type UpdateUserRequest struct { func (x *UpdateUserRequest) Reset() { *x = UpdateUserRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[5] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -540,7 +717,7 @@ func (x *UpdateUserRequest) String() string { func (*UpdateUserRequest) ProtoMessage() {} func (x *UpdateUserRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[5] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -553,7 +730,7 @@ func (x *UpdateUserRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateUserRequest.ProtoReflect.Descriptor instead. func (*UpdateUserRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{5} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{6} } func (x *UpdateUserRequest) GetUser() *User { @@ -581,7 +758,7 @@ type CreateTemporaryPasswordRequest struct { func (x *CreateTemporaryPasswordRequest) Reset() { *x = CreateTemporaryPasswordRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[6] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -594,7 +771,7 @@ func (x *CreateTemporaryPasswordRequest) String() string { func (*CreateTemporaryPasswordRequest) ProtoMessage() {} func (x *CreateTemporaryPasswordRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[6] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -607,7 +784,7 @@ func (x *CreateTemporaryPasswordRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateTemporaryPasswordRequest.ProtoReflect.Descriptor instead. func (*CreateTemporaryPasswordRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{6} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{7} } func (x *CreateTemporaryPasswordRequest) GetUserIds() *UserIdentifiers { @@ -632,7 +809,7 @@ type UpdateUserPasswordRequest struct { func (x *UpdateUserPasswordRequest) Reset() { *x = UpdateUserPasswordRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[7] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -645,7 +822,7 @@ func (x *UpdateUserPasswordRequest) String() string { func (*UpdateUserPasswordRequest) ProtoMessage() {} func (x *UpdateUserPasswordRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[7] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -658,7 +835,7 @@ func (x *UpdateUserPasswordRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateUserPasswordRequest.ProtoReflect.Descriptor instead. func (*UpdateUserPasswordRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{7} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{8} } func (x *UpdateUserPasswordRequest) GetUserIds() *UserIdentifiers { @@ -707,7 +884,7 @@ type ListUserAPIKeysRequest struct { func (x *ListUserAPIKeysRequest) Reset() { *x = ListUserAPIKeysRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[8] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -720,7 +897,7 @@ func (x *ListUserAPIKeysRequest) String() string { func (*ListUserAPIKeysRequest) ProtoMessage() {} func (x *ListUserAPIKeysRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[8] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -733,7 +910,7 @@ func (x *ListUserAPIKeysRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListUserAPIKeysRequest.ProtoReflect.Descriptor instead. func (*ListUserAPIKeysRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{8} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{9} } func (x *ListUserAPIKeysRequest) GetUserIds() *UserIdentifiers { @@ -777,7 +954,7 @@ type GetUserAPIKeyRequest struct { func (x *GetUserAPIKeyRequest) Reset() { *x = GetUserAPIKeyRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[9] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -790,7 +967,7 @@ func (x *GetUserAPIKeyRequest) String() string { func (*GetUserAPIKeyRequest) ProtoMessage() {} func (x *GetUserAPIKeyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[9] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -803,7 +980,7 @@ func (x *GetUserAPIKeyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetUserAPIKeyRequest.ProtoReflect.Descriptor instead. func (*GetUserAPIKeyRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{9} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{10} } func (x *GetUserAPIKeyRequest) GetUserIds() *UserIdentifiers { @@ -834,7 +1011,7 @@ type CreateUserAPIKeyRequest struct { func (x *CreateUserAPIKeyRequest) Reset() { *x = CreateUserAPIKeyRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[10] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -847,7 +1024,7 @@ func (x *CreateUserAPIKeyRequest) String() string { func (*CreateUserAPIKeyRequest) ProtoMessage() {} func (x *CreateUserAPIKeyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[10] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -860,7 +1037,7 @@ func (x *CreateUserAPIKeyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateUserAPIKeyRequest.ProtoReflect.Descriptor instead. func (*CreateUserAPIKeyRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{10} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{11} } func (x *CreateUserAPIKeyRequest) GetUserIds() *UserIdentifiers { @@ -905,7 +1082,7 @@ type UpdateUserAPIKeyRequest struct { func (x *UpdateUserAPIKeyRequest) Reset() { *x = UpdateUserAPIKeyRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[11] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -918,7 +1095,7 @@ func (x *UpdateUserAPIKeyRequest) String() string { func (*UpdateUserAPIKeyRequest) ProtoMessage() {} func (x *UpdateUserAPIKeyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[11] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -931,7 +1108,7 @@ func (x *UpdateUserAPIKeyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateUserAPIKeyRequest.ProtoReflect.Descriptor instead. func (*UpdateUserAPIKeyRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{11} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{12} } func (x *UpdateUserAPIKeyRequest) GetUserIds() *UserIdentifiers { @@ -967,7 +1144,7 @@ type DeleteUserAPIKeyRequest struct { func (x *DeleteUserAPIKeyRequest) Reset() { *x = DeleteUserAPIKeyRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[12] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -980,7 +1157,7 @@ func (x *DeleteUserAPIKeyRequest) String() string { func (*DeleteUserAPIKeyRequest) ProtoMessage() {} func (x *DeleteUserAPIKeyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[12] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -993,7 +1170,7 @@ func (x *DeleteUserAPIKeyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteUserAPIKeyRequest.ProtoReflect.Descriptor instead. func (*DeleteUserAPIKeyRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{12} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{13} } func (x *DeleteUserAPIKeyRequest) GetUserIds() *UserIdentifiers { @@ -1027,7 +1204,7 @@ type Invitation struct { func (x *Invitation) Reset() { *x = Invitation{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[13] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1040,7 +1217,7 @@ func (x *Invitation) String() string { func (*Invitation) ProtoMessage() {} func (x *Invitation) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[13] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1053,7 +1230,7 @@ func (x *Invitation) ProtoReflect() protoreflect.Message { // Deprecated: Use Invitation.ProtoReflect.Descriptor instead. func (*Invitation) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{13} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{14} } func (x *Invitation) GetEmail() string { @@ -1119,7 +1296,7 @@ type ListInvitationsRequest struct { func (x *ListInvitationsRequest) Reset() { *x = ListInvitationsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[14] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1132,7 +1309,7 @@ func (x *ListInvitationsRequest) String() string { func (*ListInvitationsRequest) ProtoMessage() {} func (x *ListInvitationsRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[14] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1145,7 +1322,7 @@ func (x *ListInvitationsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListInvitationsRequest.ProtoReflect.Descriptor instead. func (*ListInvitationsRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{14} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{15} } func (x *ListInvitationsRequest) GetLimit() uint32 { @@ -1173,7 +1350,7 @@ type Invitations struct { func (x *Invitations) Reset() { *x = Invitations{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[15] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1186,7 +1363,7 @@ func (x *Invitations) String() string { func (*Invitations) ProtoMessage() {} func (x *Invitations) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[15] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1199,7 +1376,7 @@ func (x *Invitations) ProtoReflect() protoreflect.Message { // Deprecated: Use Invitations.ProtoReflect.Descriptor instead. func (*Invitations) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{15} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{16} } func (x *Invitations) GetInvitations() []*Invitation { @@ -1220,7 +1397,7 @@ type SendInvitationRequest struct { func (x *SendInvitationRequest) Reset() { *x = SendInvitationRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[16] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1233,7 +1410,7 @@ func (x *SendInvitationRequest) String() string { func (*SendInvitationRequest) ProtoMessage() {} func (x *SendInvitationRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[16] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1246,7 +1423,7 @@ func (x *SendInvitationRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SendInvitationRequest.ProtoReflect.Descriptor instead. func (*SendInvitationRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{16} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{17} } func (x *SendInvitationRequest) GetEmail() string { @@ -1267,7 +1444,7 @@ type DeleteInvitationRequest struct { func (x *DeleteInvitationRequest) Reset() { *x = DeleteInvitationRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[17] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1280,7 +1457,7 @@ func (x *DeleteInvitationRequest) String() string { func (*DeleteInvitationRequest) ProtoMessage() {} func (x *DeleteInvitationRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[17] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1293,7 +1470,7 @@ func (x *DeleteInvitationRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteInvitationRequest.ProtoReflect.Descriptor instead. func (*DeleteInvitationRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{17} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{18} } func (x *DeleteInvitationRequest) GetEmail() string { @@ -1315,7 +1492,7 @@ type UserSessionIdentifiers struct { func (x *UserSessionIdentifiers) Reset() { *x = UserSessionIdentifiers{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[18] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1328,7 +1505,7 @@ func (x *UserSessionIdentifiers) String() string { func (*UserSessionIdentifiers) ProtoMessage() {} func (x *UserSessionIdentifiers) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[18] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1341,7 +1518,7 @@ func (x *UserSessionIdentifiers) ProtoReflect() protoreflect.Message { // Deprecated: Use UserSessionIdentifiers.ProtoReflect.Descriptor instead. func (*UserSessionIdentifiers) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{18} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{19} } func (x *UserSessionIdentifiers) GetUserIds() *UserIdentifiers { @@ -1375,7 +1552,7 @@ type UserSession struct { func (x *UserSession) Reset() { *x = UserSession{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[19] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1388,7 +1565,7 @@ func (x *UserSession) String() string { func (*UserSession) ProtoMessage() {} func (x *UserSession) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[19] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1401,7 +1578,7 @@ func (x *UserSession) ProtoReflect() protoreflect.Message { // Deprecated: Use UserSession.ProtoReflect.Descriptor instead. func (*UserSession) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{19} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{20} } func (x *UserSession) GetUserIds() *UserIdentifiers { @@ -1457,7 +1634,7 @@ type UserSessions struct { func (x *UserSessions) Reset() { *x = UserSessions{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[20] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1470,7 +1647,7 @@ func (x *UserSessions) String() string { func (*UserSessions) ProtoMessage() {} func (x *UserSessions) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[20] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1483,7 +1660,7 @@ func (x *UserSessions) ProtoReflect() protoreflect.Message { // Deprecated: Use UserSessions.ProtoReflect.Descriptor instead. func (*UserSessions) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{20} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{21} } func (x *UserSessions) GetSessions() []*UserSession { @@ -1511,7 +1688,7 @@ type ListUserSessionsRequest struct { func (x *ListUserSessionsRequest) Reset() { *x = ListUserSessionsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[21] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1524,7 +1701,7 @@ func (x *ListUserSessionsRequest) String() string { func (*ListUserSessionsRequest) ProtoMessage() {} func (x *ListUserSessionsRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[21] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1537,7 +1714,7 @@ func (x *ListUserSessionsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListUserSessionsRequest.ProtoReflect.Descriptor instead. func (*ListUserSessionsRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{21} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{22} } func (x *ListUserSessionsRequest) GetUserIds() *UserIdentifiers { @@ -1584,7 +1761,7 @@ type LoginToken struct { func (x *LoginToken) Reset() { *x = LoginToken{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[22] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1597,7 +1774,7 @@ func (x *LoginToken) String() string { func (*LoginToken) ProtoMessage() {} func (x *LoginToken) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[22] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1610,7 +1787,7 @@ func (x *LoginToken) ProtoReflect() protoreflect.Message { // Deprecated: Use LoginToken.ProtoReflect.Descriptor instead. func (*LoginToken) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{22} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{23} } func (x *LoginToken) GetUserIds() *UserIdentifiers { @@ -1669,7 +1846,7 @@ type CreateLoginTokenRequest struct { func (x *CreateLoginTokenRequest) Reset() { *x = CreateLoginTokenRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[23] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1682,7 +1859,7 @@ func (x *CreateLoginTokenRequest) String() string { func (*CreateLoginTokenRequest) ProtoMessage() {} func (x *CreateLoginTokenRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[23] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1695,7 +1872,7 @@ func (x *CreateLoginTokenRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateLoginTokenRequest.ProtoReflect.Descriptor instead. func (*CreateLoginTokenRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{23} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{24} } func (x *CreateLoginTokenRequest) GetUserIds() *UserIdentifiers { @@ -1725,7 +1902,7 @@ type CreateLoginTokenResponse struct { func (x *CreateLoginTokenResponse) Reset() { *x = CreateLoginTokenResponse{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[24] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1738,7 +1915,7 @@ func (x *CreateLoginTokenResponse) String() string { func (*CreateLoginTokenResponse) ProtoMessage() {} func (x *CreateLoginTokenResponse) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_user_proto_msgTypes[24] + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1751,7 +1928,7 @@ func (x *CreateLoginTokenResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateLoginTokenResponse.ProtoReflect.Descriptor instead. func (*CreateLoginTokenResponse) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{24} + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{25} } func (x *CreateLoginTokenResponse) GetToken() string { @@ -1761,377 +1938,707 @@ func (x *CreateLoginTokenResponse) GetToken() string { return "" } -var File_ttn_lorawan_v3_user_proto protoreflect.FileDescriptor +type UserConsolePreferences_DashboardLayouts struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -var file_ttn_lorawan_v3_user_proto_rawDesc = []byte{ - 0x0a, 0x19, 0x74, 0x74, 0x6e, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2f, 0x76, 0x33, - 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x74, 0x74, 0x6e, - 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x1a, 0x20, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, - 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, - 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2f, - 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x1a, 0x21, 0x74, 0x74, 0x6e, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2f, 0x76, - 0x33, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x74, 0x74, 0x6e, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, - 0x6e, 0x2f, 0x76, 0x33, 0x2f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x1a, 0x20, 0x74, 0x74, 0x6e, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2f, 0x76, 0x33, - 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x1a, 0x1c, 0x74, 0x74, 0x6e, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2f, - 0x76, 0x33, 0x2f, 0x70, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x1a, 0x1b, 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, 0xfb, 0x0b, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, - 0x43, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, - 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, - 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x10, 0xfa, - 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x28, 0x01, 0x52, - 0x03, 0x69, 0x64, 0x73, 0x12, 0x43, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, - 0x61, 0x74, 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, 0x42, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x00, 0x52, 0x09, - 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x43, 0x0a, 0x0a, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, - 0x00, 0x10, 0x00, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x43, - 0x0a, 0x0a, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x13, 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, - 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x64, 0x41, 0x74, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x2a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xd0, 0x0f, 0x52, - 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x7b, 0x0a, 0x0a, - 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x9a, 0x01, 0x2f, 0x10, 0x0a, - 0x22, 0x24, 0x72, 0x22, 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, - 0x5d, 0x28, 0x3f, 0x3a, 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, - 0x29, 0x7b, 0x32, 0x2c, 0x7d, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0a, 0x61, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x4a, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x0a, 0xfa, 0x42, - 0x05, 0x92, 0x01, 0x02, 0x10, 0x0a, 0x18, 0x01, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, - 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3b, 0x0a, 0x15, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, - 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x60, 0x01, 0x52, 0x13, 0x70, - 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x12, 0x66, 0x0a, 0x22, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x65, 0x6d, - 0x61, 0x69, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x69, - 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x09, 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, 0x1e, 0x70, 0x72, 0x69, 0x6d, - 0x61, 0x72, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x56, - 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x24, 0x0a, 0x08, 0x70, 0x61, - 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, - 0x05, 0x72, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, - 0x12, 0x54, 0x0a, 0x13, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0b, 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, 0xf2, 0xaa, 0x19, 0x04, 0x08, - 0x01, 0x10, 0x00, 0x52, 0x11, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x36, 0x0a, 0x17, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, - 0x65, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, - 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x35, - 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, - 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x35, 0x0a, 0x11, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0x80, 0x01, 0x52, 0x10, 0x73, 0x74, 0x61, 0x74, - 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x12, 0x37, 0x0a, 0x12, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x5f, - 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, - 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x11, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, - 0x61, 0x72, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x67, 0x0a, 0x1d, 0x74, - 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, - 0x64, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x10, 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, - 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x52, 0x1a, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, - 0x61, 0x72, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x41, 0x74, 0x12, 0x67, 0x0a, 0x1d, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, - 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, - 0x65, 0x73, 0x5f, 0x61, 0x74, 0x18, 0x11, 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, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, - 0x00, 0x52, 0x1a, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x50, 0x61, 0x73, 0x73, - 0x77, 0x6f, 0x72, 0x64, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x40, 0x0a, - 0x0f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, - 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x52, - 0x0e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 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, 0x15, 0x10, 0x16, 0x4a, 0x04, - 0x08, 0x16, 0x10, 0x17, 0x4a, 0x04, 0x08, 0x17, 0x10, 0x18, 0x4a, 0x04, 0x08, 0x18, 0x10, 0x19, - 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, - 0x52, 0x12, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, - 0x69, 0x6d, 0x69, 0x74, 0x22, 0x33, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x2a, 0x0a, - 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, - 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, - 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x91, 0x01, 0x0a, 0x0e, 0x47, 0x65, - 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, - 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, + ApiKey DashboardLayout `protobuf:"varint,1,opt,name=api_key,json=apiKey,proto3,enum=ttn.lorawan.v3.DashboardLayout" json:"api_key,omitempty"` + Application DashboardLayout `protobuf:"varint,2,opt,name=application,proto3,enum=ttn.lorawan.v3.DashboardLayout" json:"application,omitempty"` + Collaborator DashboardLayout `protobuf:"varint,3,opt,name=collaborator,proto3,enum=ttn.lorawan.v3.DashboardLayout" json:"collaborator,omitempty"` + EndDevice DashboardLayout `protobuf:"varint,4,opt,name=end_device,json=endDevice,proto3,enum=ttn.lorawan.v3.DashboardLayout" json:"end_device,omitempty"` + Gateway DashboardLayout `protobuf:"varint,5,opt,name=gateway,proto3,enum=ttn.lorawan.v3.DashboardLayout" json:"gateway,omitempty"` + Organization DashboardLayout `protobuf:"varint,6,opt,name=organization,proto3,enum=ttn.lorawan.v3.DashboardLayout" json:"organization,omitempty"` + Overview DashboardLayout `protobuf:"varint,7,opt,name=overview,proto3,enum=ttn.lorawan.v3.DashboardLayout" json:"overview,omitempty"` + User DashboardLayout `protobuf:"varint,8,opt,name=user,proto3,enum=ttn.lorawan.v3.DashboardLayout" json:"user,omitempty"` +} + +func (x *UserConsolePreferences_DashboardLayouts) Reset() { + *x = UserConsolePreferences_DashboardLayouts{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserConsolePreferences_DashboardLayouts) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserConsolePreferences_DashboardLayouts) ProtoMessage() {} + +func (x *UserConsolePreferences_DashboardLayouts) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[26] + 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 UserConsolePreferences_DashboardLayouts.ProtoReflect.Descriptor instead. +func (*UserConsolePreferences_DashboardLayouts) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{0, 0} +} + +func (x *UserConsolePreferences_DashboardLayouts) GetApiKey() DashboardLayout { + if x != nil { + return x.ApiKey + } + return DashboardLayout_DASHBOARD_LAYOUT_TABLE +} + +func (x *UserConsolePreferences_DashboardLayouts) GetApplication() DashboardLayout { + if x != nil { + return x.Application + } + return DashboardLayout_DASHBOARD_LAYOUT_TABLE +} + +func (x *UserConsolePreferences_DashboardLayouts) GetCollaborator() DashboardLayout { + if x != nil { + return x.Collaborator + } + return DashboardLayout_DASHBOARD_LAYOUT_TABLE +} + +func (x *UserConsolePreferences_DashboardLayouts) GetEndDevice() DashboardLayout { + if x != nil { + return x.EndDevice + } + return DashboardLayout_DASHBOARD_LAYOUT_TABLE +} + +func (x *UserConsolePreferences_DashboardLayouts) GetGateway() DashboardLayout { + if x != nil { + return x.Gateway + } + return DashboardLayout_DASHBOARD_LAYOUT_TABLE +} + +func (x *UserConsolePreferences_DashboardLayouts) GetOrganization() DashboardLayout { + if x != nil { + return x.Organization + } + return DashboardLayout_DASHBOARD_LAYOUT_TABLE +} + +func (x *UserConsolePreferences_DashboardLayouts) GetOverview() DashboardLayout { + if x != nil { + return x.Overview + } + return DashboardLayout_DASHBOARD_LAYOUT_TABLE +} + +func (x *UserConsolePreferences_DashboardLayouts) GetUser() DashboardLayout { + if x != nil { + return x.User + } + return DashboardLayout_DASHBOARD_LAYOUT_TABLE +} + +// SortBy defines the field to which the Console will sort the display of entities. +type UserConsolePreferences_SortBy struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ApiKey string `protobuf:"bytes,1,opt,name=api_key,json=apiKey,proto3" json:"api_key,omitempty"` + Application string `protobuf:"bytes,2,opt,name=application,proto3" json:"application,omitempty"` + Collaborator string `protobuf:"bytes,3,opt,name=collaborator,proto3" json:"collaborator,omitempty"` + EndDevice string `protobuf:"bytes,4,opt,name=end_device,json=endDevice,proto3" json:"end_device,omitempty"` + Gateway string `protobuf:"bytes,5,opt,name=gateway,proto3" json:"gateway,omitempty"` + Organization string `protobuf:"bytes,6,opt,name=organization,proto3" json:"organization,omitempty"` + User string `protobuf:"bytes,7,opt,name=user,proto3" json:"user,omitempty"` +} + +func (x *UserConsolePreferences_SortBy) Reset() { + *x = UserConsolePreferences_SortBy{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserConsolePreferences_SortBy) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserConsolePreferences_SortBy) ProtoMessage() {} + +func (x *UserConsolePreferences_SortBy) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_user_proto_msgTypes[27] + 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 UserConsolePreferences_SortBy.ProtoReflect.Descriptor instead. +func (*UserConsolePreferences_SortBy) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_user_proto_rawDescGZIP(), []int{0, 1} +} + +func (x *UserConsolePreferences_SortBy) GetApiKey() string { + if x != nil { + return x.ApiKey + } + return "" +} + +func (x *UserConsolePreferences_SortBy) GetApplication() string { + if x != nil { + return x.Application + } + return "" +} + +func (x *UserConsolePreferences_SortBy) GetCollaborator() string { + if x != nil { + return x.Collaborator + } + return "" +} + +func (x *UserConsolePreferences_SortBy) GetEndDevice() string { + if x != nil { + return x.EndDevice + } + return "" +} + +func (x *UserConsolePreferences_SortBy) GetGateway() string { + if x != nil { + return x.Gateway + } + return "" +} + +func (x *UserConsolePreferences_SortBy) GetOrganization() string { + if x != nil { + return x.Organization + } + return "" +} + +func (x *UserConsolePreferences_SortBy) GetUser() string { + if x != nil { + return x.User + } + return "" +} + +var File_ttn_lorawan_v3_user_proto protoreflect.FileDescriptor + +var file_ttn_lorawan_v3_user_proto_rawDesc = []byte{ + 0x0a, 0x19, 0x74, 0x74, 0x6e, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2f, 0x76, 0x33, + 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x1a, 0x20, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, + 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2f, + 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x1a, 0x20, 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2f, 0x6a, 0x73, 0x6f, + 0x6e, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x74, 0x74, 0x6e, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2f, 0x76, 0x33, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x74, 0x74, 0x6e, 0x2f, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2f, 0x76, 0x33, 0x2f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x1a, 0x20, 0x74, 0x74, 0x6e, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2f, + 0x76, 0x33, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x74, 0x74, 0x6e, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x1a, 0x1b, 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, 0xbd, 0x0d, 0x0a, 0x16, 0x55, 0x73, 0x65, + 0x72, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, + 0x63, 0x65, 0x73, 0x12, 0x41, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x5f, 0x74, + 0x68, 0x65, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x6f, 0x6e, 0x73, + 0x6f, 0x6c, 0x65, 0x54, 0x68, 0x65, 0x6d, 0x65, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, + 0x65, 0x54, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x64, 0x0a, 0x11, 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, + 0x61, 0x72, 0x64, 0x5f, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x37, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x50, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, + 0x61, 0x72, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x73, 0x52, 0x10, 0x64, 0x61, 0x73, 0x68, + 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x73, 0x12, 0x46, 0x0a, 0x07, + 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x62, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, + 0x73, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x53, 0x6f, 0x72, 0x74, 0x42, 0x79, 0x52, 0x06, 0x73, 0x6f, + 0x72, 0x74, 0x42, 0x79, 0x1a, 0x86, 0x04, 0x0a, 0x10, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, + 0x72, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x73, 0x12, 0x38, 0x0a, 0x07, 0x61, 0x70, 0x69, + 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x73, 0x68, + 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x52, 0x06, 0x61, 0x70, 0x69, + 0x4b, 0x65, 0x79, 0x12, 0x41, 0x0a, 0x0b, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, + 0x61, 0x72, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x52, 0x0b, 0x61, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x43, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, + 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, + 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x52, 0x0c, 0x63, + 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x3e, 0x0a, 0x0a, 0x65, + 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, + 0x52, 0x09, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x39, 0x0a, 0x07, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, + 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x52, 0x07, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x43, 0x0a, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, + 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x52, 0x0c, 0x6f, + 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x08, 0x6f, + 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, + 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x52, 0x08, + 0x6f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x12, 0x33, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, + 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x1a, 0x9e, 0x07, + 0x0a, 0x06, 0x53, 0x6f, 0x72, 0x74, 0x42, 0x79, 0x12, 0x78, 0x0a, 0x07, 0x61, 0x70, 0x69, 0x5f, + 0x6b, 0x65, 0x79, 0x18, 0x01, 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, 0x06, 0x61, 0x70, 0x69, 0x4b, + 0x65, 0x79, 0x12, 0x70, 0x0a, 0x0b, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x4e, 0xfa, 0x42, 0x4b, 0x72, 0x49, 0x52, 0x00, + 0x52, 0x0e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x52, 0x0f, 0x2d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 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, 0x0b, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xfa, 0x42, 0x1e, 0x72, + 0x1c, 0x52, 0x00, 0x52, 0x02, 0x69, 0x64, 0x52, 0x03, 0x2d, 0x69, 0x64, 0x52, 0x06, 0x72, 0x69, + 0x67, 0x68, 0x74, 0x73, 0x52, 0x07, 0x2d, 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x52, 0x0c, 0x63, + 0x6f, 0x6c, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0xc6, 0x01, 0x0a, 0x0a, + 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x42, 0xa6, 0x01, 0xfa, 0x42, 0xa2, 0x01, 0x72, 0x9f, 0x01, 0x52, 0x00, 0x52, 0x09, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x52, 0x0a, 0x2d, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x5f, 0x69, 0x64, 0x52, 0x08, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x65, 0x75, 0x69, 0x52, 0x09, 0x2d, + 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x65, 0x75, 0x69, 0x52, 0x07, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, + 0x69, 0x52, 0x08, 0x2d, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x52, 0x05, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x2d, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 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, 0x0c, 0x6c, 0x61, + 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x61, 0x74, 0x52, 0x0d, 0x2d, 0x6c, 0x61, 0x73, + 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x61, 0x74, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x7b, 0x0a, 0x07, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x61, 0xfa, 0x42, 0x5e, 0x72, 0x5c, 0x52, 0x00, 0x52, 0x0a, + 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x69, 0x64, 0x52, 0x0b, 0x2d, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x5f, 0x69, 0x64, 0x52, 0x0b, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x5f, 0x65, 0x75, 0x69, 0x52, 0x0c, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x65, + 0x75, 0x69, 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, 0x07, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x12, 0x74, 0x0a, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x06, 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, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0xa4, 0x01, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x8f, 0x01, 0xfa, 0x42, 0x8b, 0x01, 0x72, 0x88, 0x01, + 0x52, 0x00, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x52, 0x08, 0x2d, 0x75, 0x73, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x05, 0x2d, 0x6e, 0x61, + 0x6d, 0x65, 0x52, 0x15, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x65, 0x6d, 0x61, 0x69, + 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x16, 0x2d, 0x70, 0x72, 0x69, 0x6d, + 0x61, 0x72, 0x79, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x06, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x52, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x06, 0x2d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 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, 0x04, 0x75, 0x73, 0x65, 0x72, 0x3a, 0x08, + 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0xd4, 0x0c, 0x0a, 0x04, 0x55, 0x73, 0x65, + 0x72, 0x12, 0x43, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 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, 0x07, 0x75, 0x73, 0x65, 0x72, 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, 0xce, 0x02, - 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, - 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, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, - 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0xa6, 0x01, - 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x8f, 0x01, - 0xfa, 0x42, 0x8b, 0x01, 0x72, 0x88, 0x01, 0x52, 0x00, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, - 0x69, 0x64, 0x52, 0x08, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x52, 0x05, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x15, 0x70, 0x72, 0x69, 0x6d, 0x61, + 0x10, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x28, + 0x01, 0x52, 0x03, 0x69, 0x64, 0x73, 0x12, 0x43, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x61, 0x74, 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, 0x42, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x00, + 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x43, 0x0a, 0x0a, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x08, 0xf2, 0xaa, 0x19, + 0x04, 0x08, 0x00, 0x10, 0x00, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x12, 0x43, 0x0a, 0x0a, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x13, + 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, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xd0, + 0x0f, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x7b, + 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, + 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x9a, 0x01, 0x2f, + 0x10, 0x0a, 0x22, 0x24, 0x72, 0x22, 0x18, 0x24, 0x32, 0x1e, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, + 0x2d, 0x39, 0x5d, 0x28, 0x3f, 0x3a, 0x5b, 0x2d, 0x5d, 0x3f, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, + 0x39, 0x5d, 0x29, 0x7b, 0x32, 0x2c, 0x7d, 0x24, 0x2a, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, + 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x4a, 0x0a, 0x0c, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x0a, + 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, 0x10, 0x0a, 0x18, 0x01, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3b, 0x0a, 0x15, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x52, 0x16, 0x2d, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, - 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, - 0x06, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x06, - 0x2d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 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, - 0x03, 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, 0x04, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x64, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0x72, - 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x60, 0x01, 0x52, + 0x13, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x66, 0x0a, 0x22, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, + 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x09, 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, 0x1e, 0x70, 0x72, + 0x69, 0x6d, 0x61, 0x72, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x24, 0x0a, 0x08, + 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, + 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x12, 0x54, 0x0a, 0x13, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0b, 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, 0xf2, 0xaa, 0x19, + 0x04, 0x08, 0x01, 0x10, 0x00, 0x52, 0x11, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x36, 0x0a, 0x17, 0x72, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x75, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x72, 0x65, 0x71, 0x75, 0x69, + 0x72, 0x65, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x12, 0x35, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, + 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x35, 0x0a, 0x11, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x14, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0x80, 0x01, 0x52, 0x10, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, + 0x0a, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x12, 0x37, 0x0a, 0x12, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, + 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x11, 0x74, 0x65, 0x6d, 0x70, + 0x6f, 0x72, 0x61, 0x72, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x67, 0x0a, + 0x1d, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x10, + 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, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x52, 0x1a, 0x74, 0x65, 0x6d, 0x70, + 0x6f, 0x72, 0x61, 0x72, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x67, 0x0a, 0x1d, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, + 0x61, 0x72, 0x79, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x65, 0x78, 0x70, + 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x18, 0x11, 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, 0xf2, 0xaa, 0x19, 0x04, 0x08, + 0x01, 0x10, 0x00, 0x52, 0x1a, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x50, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, + 0x40, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x69, 0x63, 0x74, 0x75, + 0x72, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, + 0x65, 0x52, 0x0e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, + 0x65, 0x12, 0x57, 0x0a, 0x13, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x5f, 0x70, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x50, 0x72, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x12, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x50, + 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 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, 0x15, 0x10, 0x16, 0x4a, 0x04, 0x08, 0x16, 0x10, 0x17, 0x4a, + 0x04, 0x08, 0x17, 0x10, 0x18, 0x4a, 0x04, 0x08, 0x18, 0x10, 0x19, 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, 0x52, 0x12, 0x6f, 0x72, 0x67, + 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, + 0x33, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, + 0x73, 0x65, 0x72, 0x73, 0x22, 0x91, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 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, 0x07, 0x75, 0x73, 0x65, 0x72, 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, 0xce, 0x02, 0x0a, 0x10, 0x4c, 0x69, 0x73, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, + 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 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, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0xa6, 0x01, 0x0a, 0x05, 0x6f, 0x72, 0x64, + 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x8f, 0x01, 0xfa, 0x42, 0x8b, 0x01, 0x72, + 0x88, 0x01, 0x52, 0x00, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x52, 0x08, 0x2d, + 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x05, 0x2d, + 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x15, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x65, 0x6d, + 0x61, 0x69, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x16, 0x2d, 0x70, 0x72, + 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x06, 0x2d, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x52, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x52, 0x06, 0x2d, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 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, 0x03, 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, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x3a, + 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0x72, 0x0a, 0x11, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, + 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, + 0x65, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x75, 0x73, + 0x65, 0x72, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, + 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x82, 0x01, + 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, - 0x01, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x76, 0x69, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0f, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x22, 0x82, 0x01, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x42, 0x08, 0xfa, 0x42, - 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x75, 0x73, 0x65, 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, 0x22, 0x66, 0x0a, 0x1e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, - 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, - 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, - 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 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, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x22, - 0xc5, 0x01, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x61, - 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, - 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 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, 0x07, 0x75, 0x73, 0x65, 0x72, - 0x49, 0x64, 0x73, 0x12, 0x1a, 0x0a, 0x03, 0x6e, 0x65, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x03, 0x6e, 0x65, 0x77, 0x12, - 0x1a, 0x0a, 0x03, 0x6f, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, - 0x05, 0x72, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x03, 0x6f, 0x6c, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x72, - 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x41, 0x6c, - 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x93, 0x02, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, - 0x55, 0x73, 0x65, 0x72, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, - 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 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, - 0x07, 0x75, 0x73, 0x65, 0x72, 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, 0x73, 0x0a, - 0x14, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, - 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 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, 0x07, 0x75, 0x73, 0x65, 0x72, 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, 0x83, 0x02, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, - 0x72, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, - 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 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, 0x07, 0x75, 0x73, 0x65, - 0x72, 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, 0xd5, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, + 0x01, 0x52, 0x04, 0x75, 0x73, 0x65, 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, 0x22, 0x66, 0x0a, 0x1e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x65, 0x6d, 0x70, + 0x6f, 0x72, 0x61, 0x72, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 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, 0x07, 0x75, 0x73, 0x65, 0x72, 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, 0x76, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x50, - 0x49, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, - 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 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, 0x07, 0x75, 0x73, 0x65, 0x72, 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, 0x02, 0x0a, 0x0a, 0x49, 0x6e, 0x76, - 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x60, 0x01, 0x52, - 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x39, 0x0a, 0x0a, - 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x65, 0x78, - 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 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, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, - 0x18, 0x05, 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, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3b, 0x0a, - 0x0b, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 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, 0x0a, - 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x40, 0x0a, 0x0b, 0x61, 0x63, - 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x22, 0xc5, 0x01, 0x0a, 0x19, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 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, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x1a, + 0x0a, 0x03, 0x6e, 0x65, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, + 0x72, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x03, 0x6e, 0x65, 0x77, 0x12, 0x1a, 0x0a, 0x03, 0x6f, 0x6c, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xe8, + 0x07, 0x52, 0x03, 0x6f, 0x6c, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, + 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0f, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x41, 0x6c, 0x6c, 0x41, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x22, 0x93, 0x02, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x41, + 0x50, 0x49, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, + 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, - 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x79, 0x22, 0x4c, 0x0a, 0x16, - 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, - 0x01, 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, 0x02, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x22, 0x4b, 0x0a, 0x0b, 0x49, 0x6e, - 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3c, 0x0a, 0x0b, 0x69, 0x6e, 0x76, - 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, - 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x69, 0x6e, 0x76, 0x69, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x36, 0x0a, 0x15, 0x53, 0x65, 0x6e, 0x64, 0x49, - 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x1d, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x60, 0x01, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, - 0x38, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x05, 0x65, 0x6d, - 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, - 0x60, 0x01, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x86, 0x01, 0x0a, 0x16, 0x55, 0x73, - 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x69, 0x65, 0x72, 0x73, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 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, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x26, 0x0a, 0x0a, 0x73, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, - 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x40, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x49, 0x64, 0x22, 0xd3, 0x02, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, - 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 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, - 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x26, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, - 0x04, 0x72, 0x02, 0x18, 0x40, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, + 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, 0x73, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x55, + 0x73, 0x65, 0x72, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 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, 0x07, 0x75, + 0x73, 0x65, 0x72, 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, 0x83, 0x02, + 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x50, 0x49, 0x4b, + 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, + 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 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, 0x07, 0x75, 0x73, 0x65, 0x72, 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, 0xd5, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, + 0x65, 0x72, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 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, 0x07, 0x75, 0x73, + 0x65, 0x72, 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, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 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, 0x52, 0x09, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, - 0x73, 0x5f, 0x61, 0x74, 0x18, 0x05, 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, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, - 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x63, - 0x72, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0x47, 0x0a, 0x0c, 0x55, 0x73, 0x65, 0x72, - 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x37, 0x0a, 0x08, 0x73, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x74, 0x6e, + 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, 0x76, 0x0a, 0x17, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, + 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 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, 0x07, 0x75, 0x73, 0x65, 0x72, 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, 0x02, 0x0a, 0x0a, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x60, 0x01, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, + 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, + 0x65, 0x73, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, + 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 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, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, + 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 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, 0x09, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3b, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, + 0x70, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 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, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x70, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x40, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, + 0x64, 0x5f, 0x62, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, - 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x22, 0xcb, 0x01, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x61, 0x63, 0x63, + 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x79, 0x22, 0x4c, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x49, + 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1e, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x01, 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, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x04, 0x70, 0x61, 0x67, 0x65, 0x22, 0x4b, 0x0a, 0x0b, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3c, 0x0a, 0x0b, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x22, 0x36, 0x0a, 0x15, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x05, 0x65, + 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, + 0x02, 0x60, 0x01, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x38, 0x0a, 0x17, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x60, 0x01, 0x52, 0x05, 0x65, + 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x86, 0x01, 0x0a, 0x16, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x12, + 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 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, 0x07, 0x75, 0x73, + 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x26, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, + 0x18, 0x40, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xd3, 0x02, + 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 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, 0x07, 0x75, 0x73, 0x65, 0x72, - 0x49, 0x64, 0x73, 0x12, 0x36, 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x20, 0xfa, 0x42, 0x1d, 0x72, 0x1b, 0x52, 0x00, 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, 0x03, 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, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x22, - 0xad, 0x02, 0x0a, 0x0a, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x44, - 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 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, 0x07, 0x75, 0x73, 0x65, - 0x72, 0x49, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, - 0x61, 0x74, 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, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, - 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, + 0x49, 0x64, 0x73, 0x12, 0x26, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x40, + 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x64, 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, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, + 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x18, + 0x05, 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, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x25, 0x0a, 0x0e, + 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x63, + 0x72, 0x65, 0x74, 0x22, 0x47, 0x0a, 0x0c, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x37, 0x0a, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x52, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xcb, 0x01, 0x0a, + 0x17, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 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, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x36, + 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x20, 0xfa, + 0x42, 0x1d, 0x72, 0x1b, 0x52, 0x00, 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, + 0x03, 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, 0x04, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x22, 0xad, 0x02, 0x0a, 0x0a, 0x4c, + 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, + 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 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, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, + 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 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, - 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x65, 0x78, - 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x65, 0x78, 0x70, 0x69, - 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x75, - 0x73, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x75, 0x73, 0x65, 0x64, 0x22, - 0x7e, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, - 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 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, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, - 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x6b, 0x69, 0x70, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x22, - 0x30, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 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, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 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, 0x52, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x64, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x75, 0x73, 0x65, 0x64, 0x22, 0x7e, 0x0a, 0x17, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 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, 0x07, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, + 0x6b, 0x69, 0x70, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x09, 0x73, 0x6b, 0x69, 0x70, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x30, 0x0a, 0x18, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2a, 0x70, 0x0a, 0x0c, + 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x54, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x14, + 0x43, 0x4f, 0x4e, 0x53, 0x4f, 0x4c, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4d, 0x45, 0x5f, 0x53, 0x59, + 0x53, 0x54, 0x45, 0x4d, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x4f, 0x4e, 0x53, 0x4f, 0x4c, + 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4d, 0x45, 0x5f, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x10, 0x01, 0x12, + 0x16, 0x0a, 0x12, 0x43, 0x4f, 0x4e, 0x53, 0x4f, 0x4c, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4d, 0x45, + 0x5f, 0x44, 0x41, 0x52, 0x4b, 0x10, 0x02, 0x1a, 0x15, 0xea, 0xaa, 0x19, 0x11, 0x18, 0x01, 0x2a, + 0x0d, 0x43, 0x4f, 0x4e, 0x53, 0x4f, 0x4c, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4d, 0x45, 0x2a, 0x7d, + 0x0a, 0x0f, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, + 0x74, 0x12, 0x1a, 0x0a, 0x16, 0x44, 0x41, 0x53, 0x48, 0x42, 0x4f, 0x41, 0x52, 0x44, 0x5f, 0x4c, + 0x41, 0x59, 0x4f, 0x55, 0x54, 0x5f, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x19, 0x0a, + 0x15, 0x44, 0x41, 0x53, 0x48, 0x42, 0x4f, 0x41, 0x52, 0x44, 0x5f, 0x4c, 0x41, 0x59, 0x4f, 0x55, + 0x54, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x44, 0x41, 0x53, 0x48, + 0x42, 0x4f, 0x41, 0x52, 0x44, 0x5f, 0x4c, 0x41, 0x59, 0x4f, 0x55, 0x54, 0x5f, 0x47, 0x52, 0x49, + 0x44, 0x10, 0x02, 0x1a, 0x18, 0xea, 0xaa, 0x19, 0x14, 0x18, 0x01, 0x2a, 0x10, 0x44, 0x41, 0x53, + 0x48, 0x42, 0x4f, 0x41, 0x52, 0x44, 0x5f, 0x4c, 0x41, 0x59, 0x4f, 0x55, 0x54, 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 ( @@ -2146,97 +2653,115 @@ func file_ttn_lorawan_v3_user_proto_rawDescGZIP() []byte { return file_ttn_lorawan_v3_user_proto_rawDescData } -var file_ttn_lorawan_v3_user_proto_msgTypes = make([]protoimpl.MessageInfo, 26) +var file_ttn_lorawan_v3_user_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_ttn_lorawan_v3_user_proto_msgTypes = make([]protoimpl.MessageInfo, 29) var file_ttn_lorawan_v3_user_proto_goTypes = []interface{}{ - (*User)(nil), // 0: ttn.lorawan.v3.User - (*Users)(nil), // 1: ttn.lorawan.v3.Users - (*GetUserRequest)(nil), // 2: ttn.lorawan.v3.GetUserRequest - (*ListUsersRequest)(nil), // 3: ttn.lorawan.v3.ListUsersRequest - (*CreateUserRequest)(nil), // 4: ttn.lorawan.v3.CreateUserRequest - (*UpdateUserRequest)(nil), // 5: ttn.lorawan.v3.UpdateUserRequest - (*CreateTemporaryPasswordRequest)(nil), // 6: ttn.lorawan.v3.CreateTemporaryPasswordRequest - (*UpdateUserPasswordRequest)(nil), // 7: ttn.lorawan.v3.UpdateUserPasswordRequest - (*ListUserAPIKeysRequest)(nil), // 8: ttn.lorawan.v3.ListUserAPIKeysRequest - (*GetUserAPIKeyRequest)(nil), // 9: ttn.lorawan.v3.GetUserAPIKeyRequest - (*CreateUserAPIKeyRequest)(nil), // 10: ttn.lorawan.v3.CreateUserAPIKeyRequest - (*UpdateUserAPIKeyRequest)(nil), // 11: ttn.lorawan.v3.UpdateUserAPIKeyRequest - (*DeleteUserAPIKeyRequest)(nil), // 12: ttn.lorawan.v3.DeleteUserAPIKeyRequest - (*Invitation)(nil), // 13: ttn.lorawan.v3.Invitation - (*ListInvitationsRequest)(nil), // 14: ttn.lorawan.v3.ListInvitationsRequest - (*Invitations)(nil), // 15: ttn.lorawan.v3.Invitations - (*SendInvitationRequest)(nil), // 16: ttn.lorawan.v3.SendInvitationRequest - (*DeleteInvitationRequest)(nil), // 17: ttn.lorawan.v3.DeleteInvitationRequest - (*UserSessionIdentifiers)(nil), // 18: ttn.lorawan.v3.UserSessionIdentifiers - (*UserSession)(nil), // 19: ttn.lorawan.v3.UserSession - (*UserSessions)(nil), // 20: ttn.lorawan.v3.UserSessions - (*ListUserSessionsRequest)(nil), // 21: ttn.lorawan.v3.ListUserSessionsRequest - (*LoginToken)(nil), // 22: ttn.lorawan.v3.LoginToken - (*CreateLoginTokenRequest)(nil), // 23: ttn.lorawan.v3.CreateLoginTokenRequest - (*CreateLoginTokenResponse)(nil), // 24: ttn.lorawan.v3.CreateLoginTokenResponse - nil, // 25: ttn.lorawan.v3.User.AttributesEntry - (*UserIdentifiers)(nil), // 26: ttn.lorawan.v3.UserIdentifiers - (*timestamppb.Timestamp)(nil), // 27: google.protobuf.Timestamp - (*ContactInfo)(nil), // 28: ttn.lorawan.v3.ContactInfo - (State)(0), // 29: ttn.lorawan.v3.State - (*Picture)(nil), // 30: ttn.lorawan.v3.Picture - (*fieldmaskpb.FieldMask)(nil), // 31: google.protobuf.FieldMask - (Right)(0), // 32: ttn.lorawan.v3.Right - (*APIKey)(nil), // 33: ttn.lorawan.v3.APIKey + (ConsoleTheme)(0), // 0: ttn.lorawan.v3.ConsoleTheme + (DashboardLayout)(0), // 1: ttn.lorawan.v3.DashboardLayout + (*UserConsolePreferences)(nil), // 2: ttn.lorawan.v3.UserConsolePreferences + (*User)(nil), // 3: ttn.lorawan.v3.User + (*Users)(nil), // 4: ttn.lorawan.v3.Users + (*GetUserRequest)(nil), // 5: ttn.lorawan.v3.GetUserRequest + (*ListUsersRequest)(nil), // 6: ttn.lorawan.v3.ListUsersRequest + (*CreateUserRequest)(nil), // 7: ttn.lorawan.v3.CreateUserRequest + (*UpdateUserRequest)(nil), // 8: ttn.lorawan.v3.UpdateUserRequest + (*CreateTemporaryPasswordRequest)(nil), // 9: ttn.lorawan.v3.CreateTemporaryPasswordRequest + (*UpdateUserPasswordRequest)(nil), // 10: ttn.lorawan.v3.UpdateUserPasswordRequest + (*ListUserAPIKeysRequest)(nil), // 11: ttn.lorawan.v3.ListUserAPIKeysRequest + (*GetUserAPIKeyRequest)(nil), // 12: ttn.lorawan.v3.GetUserAPIKeyRequest + (*CreateUserAPIKeyRequest)(nil), // 13: ttn.lorawan.v3.CreateUserAPIKeyRequest + (*UpdateUserAPIKeyRequest)(nil), // 14: ttn.lorawan.v3.UpdateUserAPIKeyRequest + (*DeleteUserAPIKeyRequest)(nil), // 15: ttn.lorawan.v3.DeleteUserAPIKeyRequest + (*Invitation)(nil), // 16: ttn.lorawan.v3.Invitation + (*ListInvitationsRequest)(nil), // 17: ttn.lorawan.v3.ListInvitationsRequest + (*Invitations)(nil), // 18: ttn.lorawan.v3.Invitations + (*SendInvitationRequest)(nil), // 19: ttn.lorawan.v3.SendInvitationRequest + (*DeleteInvitationRequest)(nil), // 20: ttn.lorawan.v3.DeleteInvitationRequest + (*UserSessionIdentifiers)(nil), // 21: ttn.lorawan.v3.UserSessionIdentifiers + (*UserSession)(nil), // 22: ttn.lorawan.v3.UserSession + (*UserSessions)(nil), // 23: ttn.lorawan.v3.UserSessions + (*ListUserSessionsRequest)(nil), // 24: ttn.lorawan.v3.ListUserSessionsRequest + (*LoginToken)(nil), // 25: ttn.lorawan.v3.LoginToken + (*CreateLoginTokenRequest)(nil), // 26: ttn.lorawan.v3.CreateLoginTokenRequest + (*CreateLoginTokenResponse)(nil), // 27: ttn.lorawan.v3.CreateLoginTokenResponse + (*UserConsolePreferences_DashboardLayouts)(nil), // 28: ttn.lorawan.v3.UserConsolePreferences.DashboardLayouts + (*UserConsolePreferences_SortBy)(nil), // 29: ttn.lorawan.v3.UserConsolePreferences.SortBy + nil, // 30: ttn.lorawan.v3.User.AttributesEntry + (*UserIdentifiers)(nil), // 31: ttn.lorawan.v3.UserIdentifiers + (*timestamppb.Timestamp)(nil), // 32: google.protobuf.Timestamp + (*ContactInfo)(nil), // 33: ttn.lorawan.v3.ContactInfo + (State)(0), // 34: ttn.lorawan.v3.State + (*Picture)(nil), // 35: ttn.lorawan.v3.Picture + (*fieldmaskpb.FieldMask)(nil), // 36: google.protobuf.FieldMask + (Right)(0), // 37: ttn.lorawan.v3.Right + (*APIKey)(nil), // 38: ttn.lorawan.v3.APIKey } var file_ttn_lorawan_v3_user_proto_depIdxs = []int32{ - 26, // 0: ttn.lorawan.v3.User.ids:type_name -> ttn.lorawan.v3.UserIdentifiers - 27, // 1: ttn.lorawan.v3.User.created_at:type_name -> google.protobuf.Timestamp - 27, // 2: ttn.lorawan.v3.User.updated_at:type_name -> google.protobuf.Timestamp - 27, // 3: ttn.lorawan.v3.User.deleted_at:type_name -> google.protobuf.Timestamp - 25, // 4: ttn.lorawan.v3.User.attributes:type_name -> ttn.lorawan.v3.User.AttributesEntry - 28, // 5: ttn.lorawan.v3.User.contact_info:type_name -> ttn.lorawan.v3.ContactInfo - 27, // 6: ttn.lorawan.v3.User.primary_email_address_validated_at:type_name -> google.protobuf.Timestamp - 27, // 7: ttn.lorawan.v3.User.password_updated_at:type_name -> google.protobuf.Timestamp - 29, // 8: ttn.lorawan.v3.User.state:type_name -> ttn.lorawan.v3.State - 27, // 9: ttn.lorawan.v3.User.temporary_password_created_at:type_name -> google.protobuf.Timestamp - 27, // 10: ttn.lorawan.v3.User.temporary_password_expires_at:type_name -> google.protobuf.Timestamp - 30, // 11: ttn.lorawan.v3.User.profile_picture:type_name -> ttn.lorawan.v3.Picture - 0, // 12: ttn.lorawan.v3.Users.users:type_name -> ttn.lorawan.v3.User - 26, // 13: ttn.lorawan.v3.GetUserRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers - 31, // 14: ttn.lorawan.v3.GetUserRequest.field_mask:type_name -> google.protobuf.FieldMask - 31, // 15: ttn.lorawan.v3.ListUsersRequest.field_mask:type_name -> google.protobuf.FieldMask - 0, // 16: ttn.lorawan.v3.CreateUserRequest.user:type_name -> ttn.lorawan.v3.User - 0, // 17: ttn.lorawan.v3.UpdateUserRequest.user:type_name -> ttn.lorawan.v3.User - 31, // 18: ttn.lorawan.v3.UpdateUserRequest.field_mask:type_name -> google.protobuf.FieldMask - 26, // 19: ttn.lorawan.v3.CreateTemporaryPasswordRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers - 26, // 20: ttn.lorawan.v3.UpdateUserPasswordRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers - 26, // 21: ttn.lorawan.v3.ListUserAPIKeysRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers - 26, // 22: ttn.lorawan.v3.GetUserAPIKeyRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers - 26, // 23: ttn.lorawan.v3.CreateUserAPIKeyRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers - 32, // 24: ttn.lorawan.v3.CreateUserAPIKeyRequest.rights:type_name -> ttn.lorawan.v3.Right - 27, // 25: ttn.lorawan.v3.CreateUserAPIKeyRequest.expires_at:type_name -> google.protobuf.Timestamp - 26, // 26: ttn.lorawan.v3.UpdateUserAPIKeyRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers - 33, // 27: ttn.lorawan.v3.UpdateUserAPIKeyRequest.api_key:type_name -> ttn.lorawan.v3.APIKey - 31, // 28: ttn.lorawan.v3.UpdateUserAPIKeyRequest.field_mask:type_name -> google.protobuf.FieldMask - 26, // 29: ttn.lorawan.v3.DeleteUserAPIKeyRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers - 27, // 30: ttn.lorawan.v3.Invitation.expires_at:type_name -> google.protobuf.Timestamp - 27, // 31: ttn.lorawan.v3.Invitation.created_at:type_name -> google.protobuf.Timestamp - 27, // 32: ttn.lorawan.v3.Invitation.updated_at:type_name -> google.protobuf.Timestamp - 27, // 33: ttn.lorawan.v3.Invitation.accepted_at:type_name -> google.protobuf.Timestamp - 26, // 34: ttn.lorawan.v3.Invitation.accepted_by:type_name -> ttn.lorawan.v3.UserIdentifiers - 13, // 35: ttn.lorawan.v3.Invitations.invitations:type_name -> ttn.lorawan.v3.Invitation - 26, // 36: ttn.lorawan.v3.UserSessionIdentifiers.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers - 26, // 37: ttn.lorawan.v3.UserSession.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers - 27, // 38: ttn.lorawan.v3.UserSession.created_at:type_name -> google.protobuf.Timestamp - 27, // 39: ttn.lorawan.v3.UserSession.updated_at:type_name -> google.protobuf.Timestamp - 27, // 40: ttn.lorawan.v3.UserSession.expires_at:type_name -> google.protobuf.Timestamp - 19, // 41: ttn.lorawan.v3.UserSessions.sessions:type_name -> ttn.lorawan.v3.UserSession - 26, // 42: ttn.lorawan.v3.ListUserSessionsRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers - 26, // 43: ttn.lorawan.v3.LoginToken.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers - 27, // 44: ttn.lorawan.v3.LoginToken.created_at:type_name -> google.protobuf.Timestamp - 27, // 45: ttn.lorawan.v3.LoginToken.updated_at:type_name -> google.protobuf.Timestamp - 27, // 46: ttn.lorawan.v3.LoginToken.expires_at:type_name -> google.protobuf.Timestamp - 26, // 47: ttn.lorawan.v3.CreateLoginTokenRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers - 48, // [48:48] is the sub-list for method output_type - 48, // [48:48] is the sub-list for method input_type - 48, // [48:48] is the sub-list for extension type_name - 48, // [48:48] is the sub-list for extension extendee - 0, // [0:48] is the sub-list for field type_name + 0, // 0: ttn.lorawan.v3.UserConsolePreferences.console_theme:type_name -> ttn.lorawan.v3.ConsoleTheme + 28, // 1: ttn.lorawan.v3.UserConsolePreferences.dashboard_layouts:type_name -> ttn.lorawan.v3.UserConsolePreferences.DashboardLayouts + 29, // 2: ttn.lorawan.v3.UserConsolePreferences.sort_by:type_name -> ttn.lorawan.v3.UserConsolePreferences.SortBy + 31, // 3: ttn.lorawan.v3.User.ids:type_name -> ttn.lorawan.v3.UserIdentifiers + 32, // 4: ttn.lorawan.v3.User.created_at:type_name -> google.protobuf.Timestamp + 32, // 5: ttn.lorawan.v3.User.updated_at:type_name -> google.protobuf.Timestamp + 32, // 6: ttn.lorawan.v3.User.deleted_at:type_name -> google.protobuf.Timestamp + 30, // 7: ttn.lorawan.v3.User.attributes:type_name -> ttn.lorawan.v3.User.AttributesEntry + 33, // 8: ttn.lorawan.v3.User.contact_info:type_name -> ttn.lorawan.v3.ContactInfo + 32, // 9: ttn.lorawan.v3.User.primary_email_address_validated_at:type_name -> google.protobuf.Timestamp + 32, // 10: ttn.lorawan.v3.User.password_updated_at:type_name -> google.protobuf.Timestamp + 34, // 11: ttn.lorawan.v3.User.state:type_name -> ttn.lorawan.v3.State + 32, // 12: ttn.lorawan.v3.User.temporary_password_created_at:type_name -> google.protobuf.Timestamp + 32, // 13: ttn.lorawan.v3.User.temporary_password_expires_at:type_name -> google.protobuf.Timestamp + 35, // 14: ttn.lorawan.v3.User.profile_picture:type_name -> ttn.lorawan.v3.Picture + 2, // 15: ttn.lorawan.v3.User.console_preferences:type_name -> ttn.lorawan.v3.UserConsolePreferences + 3, // 16: ttn.lorawan.v3.Users.users:type_name -> ttn.lorawan.v3.User + 31, // 17: ttn.lorawan.v3.GetUserRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers + 36, // 18: ttn.lorawan.v3.GetUserRequest.field_mask:type_name -> google.protobuf.FieldMask + 36, // 19: ttn.lorawan.v3.ListUsersRequest.field_mask:type_name -> google.protobuf.FieldMask + 3, // 20: ttn.lorawan.v3.CreateUserRequest.user:type_name -> ttn.lorawan.v3.User + 3, // 21: ttn.lorawan.v3.UpdateUserRequest.user:type_name -> ttn.lorawan.v3.User + 36, // 22: ttn.lorawan.v3.UpdateUserRequest.field_mask:type_name -> google.protobuf.FieldMask + 31, // 23: ttn.lorawan.v3.CreateTemporaryPasswordRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers + 31, // 24: ttn.lorawan.v3.UpdateUserPasswordRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers + 31, // 25: ttn.lorawan.v3.ListUserAPIKeysRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers + 31, // 26: ttn.lorawan.v3.GetUserAPIKeyRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers + 31, // 27: ttn.lorawan.v3.CreateUserAPIKeyRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers + 37, // 28: ttn.lorawan.v3.CreateUserAPIKeyRequest.rights:type_name -> ttn.lorawan.v3.Right + 32, // 29: ttn.lorawan.v3.CreateUserAPIKeyRequest.expires_at:type_name -> google.protobuf.Timestamp + 31, // 30: ttn.lorawan.v3.UpdateUserAPIKeyRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers + 38, // 31: ttn.lorawan.v3.UpdateUserAPIKeyRequest.api_key:type_name -> ttn.lorawan.v3.APIKey + 36, // 32: ttn.lorawan.v3.UpdateUserAPIKeyRequest.field_mask:type_name -> google.protobuf.FieldMask + 31, // 33: ttn.lorawan.v3.DeleteUserAPIKeyRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers + 32, // 34: ttn.lorawan.v3.Invitation.expires_at:type_name -> google.protobuf.Timestamp + 32, // 35: ttn.lorawan.v3.Invitation.created_at:type_name -> google.protobuf.Timestamp + 32, // 36: ttn.lorawan.v3.Invitation.updated_at:type_name -> google.protobuf.Timestamp + 32, // 37: ttn.lorawan.v3.Invitation.accepted_at:type_name -> google.protobuf.Timestamp + 31, // 38: ttn.lorawan.v3.Invitation.accepted_by:type_name -> ttn.lorawan.v3.UserIdentifiers + 16, // 39: ttn.lorawan.v3.Invitations.invitations:type_name -> ttn.lorawan.v3.Invitation + 31, // 40: ttn.lorawan.v3.UserSessionIdentifiers.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers + 31, // 41: ttn.lorawan.v3.UserSession.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers + 32, // 42: ttn.lorawan.v3.UserSession.created_at:type_name -> google.protobuf.Timestamp + 32, // 43: ttn.lorawan.v3.UserSession.updated_at:type_name -> google.protobuf.Timestamp + 32, // 44: ttn.lorawan.v3.UserSession.expires_at:type_name -> google.protobuf.Timestamp + 22, // 45: ttn.lorawan.v3.UserSessions.sessions:type_name -> ttn.lorawan.v3.UserSession + 31, // 46: ttn.lorawan.v3.ListUserSessionsRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers + 31, // 47: ttn.lorawan.v3.LoginToken.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers + 32, // 48: ttn.lorawan.v3.LoginToken.created_at:type_name -> google.protobuf.Timestamp + 32, // 49: ttn.lorawan.v3.LoginToken.updated_at:type_name -> google.protobuf.Timestamp + 32, // 50: ttn.lorawan.v3.LoginToken.expires_at:type_name -> google.protobuf.Timestamp + 31, // 51: ttn.lorawan.v3.CreateLoginTokenRequest.user_ids:type_name -> ttn.lorawan.v3.UserIdentifiers + 1, // 52: ttn.lorawan.v3.UserConsolePreferences.DashboardLayouts.api_key:type_name -> ttn.lorawan.v3.DashboardLayout + 1, // 53: ttn.lorawan.v3.UserConsolePreferences.DashboardLayouts.application:type_name -> ttn.lorawan.v3.DashboardLayout + 1, // 54: ttn.lorawan.v3.UserConsolePreferences.DashboardLayouts.collaborator:type_name -> ttn.lorawan.v3.DashboardLayout + 1, // 55: ttn.lorawan.v3.UserConsolePreferences.DashboardLayouts.end_device:type_name -> ttn.lorawan.v3.DashboardLayout + 1, // 56: ttn.lorawan.v3.UserConsolePreferences.DashboardLayouts.gateway:type_name -> ttn.lorawan.v3.DashboardLayout + 1, // 57: ttn.lorawan.v3.UserConsolePreferences.DashboardLayouts.organization:type_name -> ttn.lorawan.v3.DashboardLayout + 1, // 58: ttn.lorawan.v3.UserConsolePreferences.DashboardLayouts.overview:type_name -> ttn.lorawan.v3.DashboardLayout + 1, // 59: ttn.lorawan.v3.UserConsolePreferences.DashboardLayouts.user:type_name -> ttn.lorawan.v3.DashboardLayout + 60, // [60:60] is the sub-list for method output_type + 60, // [60:60] is the sub-list for method input_type + 60, // [60:60] is the sub-list for extension type_name + 60, // [60:60] is the sub-list for extension extendee + 0, // [0:60] is the sub-list for field type_name } func init() { file_ttn_lorawan_v3_user_proto_init() } @@ -2251,7 +2776,7 @@ func file_ttn_lorawan_v3_user_proto_init() { file_ttn_lorawan_v3_rights_proto_init() if !protoimpl.UnsafeEnabled { file_ttn_lorawan_v3_user_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*User); i { + switch v := v.(*UserConsolePreferences); i { case 0: return &v.state case 1: @@ -2263,7 +2788,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Users); i { + switch v := v.(*User); i { case 0: return &v.state case 1: @@ -2275,7 +2800,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetUserRequest); i { + switch v := v.(*Users); i { case 0: return &v.state case 1: @@ -2287,7 +2812,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListUsersRequest); i { + switch v := v.(*GetUserRequest); i { case 0: return &v.state case 1: @@ -2299,7 +2824,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateUserRequest); i { + switch v := v.(*ListUsersRequest); i { case 0: return &v.state case 1: @@ -2311,7 +2836,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateUserRequest); i { + switch v := v.(*CreateUserRequest); i { case 0: return &v.state case 1: @@ -2323,7 +2848,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateTemporaryPasswordRequest); i { + switch v := v.(*UpdateUserRequest); i { case 0: return &v.state case 1: @@ -2335,7 +2860,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateUserPasswordRequest); i { + switch v := v.(*CreateTemporaryPasswordRequest); i { case 0: return &v.state case 1: @@ -2347,7 +2872,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListUserAPIKeysRequest); i { + switch v := v.(*UpdateUserPasswordRequest); i { case 0: return &v.state case 1: @@ -2359,7 +2884,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetUserAPIKeyRequest); i { + switch v := v.(*ListUserAPIKeysRequest); i { case 0: return &v.state case 1: @@ -2371,7 +2896,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateUserAPIKeyRequest); i { + switch v := v.(*GetUserAPIKeyRequest); i { case 0: return &v.state case 1: @@ -2383,7 +2908,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateUserAPIKeyRequest); i { + switch v := v.(*CreateUserAPIKeyRequest); i { case 0: return &v.state case 1: @@ -2395,7 +2920,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteUserAPIKeyRequest); i { + switch v := v.(*UpdateUserAPIKeyRequest); i { case 0: return &v.state case 1: @@ -2407,7 +2932,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Invitation); i { + switch v := v.(*DeleteUserAPIKeyRequest); i { case 0: return &v.state case 1: @@ -2419,7 +2944,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListInvitationsRequest); i { + switch v := v.(*Invitation); i { case 0: return &v.state case 1: @@ -2431,7 +2956,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Invitations); i { + switch v := v.(*ListInvitationsRequest); i { case 0: return &v.state case 1: @@ -2443,7 +2968,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SendInvitationRequest); i { + switch v := v.(*Invitations); i { case 0: return &v.state case 1: @@ -2455,7 +2980,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteInvitationRequest); i { + switch v := v.(*SendInvitationRequest); i { case 0: return &v.state case 1: @@ -2467,7 +2992,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UserSessionIdentifiers); i { + switch v := v.(*DeleteInvitationRequest); i { case 0: return &v.state case 1: @@ -2479,7 +3004,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UserSession); i { + switch v := v.(*UserSessionIdentifiers); i { case 0: return &v.state case 1: @@ -2491,7 +3016,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UserSessions); i { + switch v := v.(*UserSession); i { case 0: return &v.state case 1: @@ -2503,7 +3028,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListUserSessionsRequest); i { + switch v := v.(*UserSessions); i { case 0: return &v.state case 1: @@ -2515,7 +3040,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LoginToken); i { + switch v := v.(*ListUserSessionsRequest); i { case 0: return &v.state case 1: @@ -2527,7 +3052,7 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateLoginTokenRequest); i { + switch v := v.(*LoginToken); i { case 0: return &v.state case 1: @@ -2539,6 +3064,18 @@ func file_ttn_lorawan_v3_user_proto_init() { } } file_ttn_lorawan_v3_user_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateLoginTokenRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_user_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CreateLoginTokenResponse); i { case 0: return &v.state @@ -2550,19 +3087,44 @@ func file_ttn_lorawan_v3_user_proto_init() { return nil } } + file_ttn_lorawan_v3_user_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserConsolePreferences_DashboardLayouts); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_user_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserConsolePreferences_SortBy); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_ttn_lorawan_v3_user_proto_rawDesc, - NumEnums: 0, - NumMessages: 26, + NumEnums: 2, + NumMessages: 29, NumExtensions: 0, NumServices: 0, }, GoTypes: file_ttn_lorawan_v3_user_proto_goTypes, DependencyIndexes: file_ttn_lorawan_v3_user_proto_depIdxs, + EnumInfos: file_ttn_lorawan_v3_user_proto_enumTypes, MessageInfos: file_ttn_lorawan_v3_user_proto_msgTypes, }.Build() File_ttn_lorawan_v3_user_proto = out.File diff --git a/pkg/ttnpb/user.pb.paths.fm.go b/pkg/ttnpb/user.pb.paths.fm.go index 1fa13e7f5b..83b45168f5 100644 --- a/pkg/ttnpb/user.pb.paths.fm.go +++ b/pkg/ttnpb/user.pb.paths.fm.go @@ -2,9 +2,54 @@ package ttnpb +var UserConsolePreferencesFieldPathsNested = []string{ + "console_theme", + "dashboard_layouts", + "dashboard_layouts.api_key", + "dashboard_layouts.application", + "dashboard_layouts.collaborator", + "dashboard_layouts.end_device", + "dashboard_layouts.gateway", + "dashboard_layouts.organization", + "dashboard_layouts.overview", + "dashboard_layouts.user", + "sort_by", + "sort_by.api_key", + "sort_by.application", + "sort_by.collaborator", + "sort_by.end_device", + "sort_by.gateway", + "sort_by.organization", + "sort_by.user", +} + +var UserConsolePreferencesFieldPathsTopLevel = []string{ + "console_theme", + "dashboard_layouts", + "sort_by", +} var UserFieldPathsNested = []string{ "admin", "attributes", + "console_preferences", + "console_preferences.console_theme", + "console_preferences.dashboard_layouts", + "console_preferences.dashboard_layouts.api_key", + "console_preferences.dashboard_layouts.application", + "console_preferences.dashboard_layouts.collaborator", + "console_preferences.dashboard_layouts.end_device", + "console_preferences.dashboard_layouts.gateway", + "console_preferences.dashboard_layouts.organization", + "console_preferences.dashboard_layouts.overview", + "console_preferences.dashboard_layouts.user", + "console_preferences.sort_by", + "console_preferences.sort_by.api_key", + "console_preferences.sort_by.application", + "console_preferences.sort_by.collaborator", + "console_preferences.sort_by.end_device", + "console_preferences.sort_by.gateway", + "console_preferences.sort_by.organization", + "console_preferences.sort_by.user", "contact_info", "created_at", "deleted_at", @@ -34,6 +79,7 @@ var UserFieldPathsNested = []string{ var UserFieldPathsTopLevel = []string{ "admin", "attributes", + "console_preferences", "contact_info", "created_at", "deleted_at", @@ -91,6 +137,25 @@ var CreateUserRequestFieldPathsNested = []string{ "user", "user.admin", "user.attributes", + "user.console_preferences", + "user.console_preferences.console_theme", + "user.console_preferences.dashboard_layouts", + "user.console_preferences.dashboard_layouts.api_key", + "user.console_preferences.dashboard_layouts.application", + "user.console_preferences.dashboard_layouts.collaborator", + "user.console_preferences.dashboard_layouts.end_device", + "user.console_preferences.dashboard_layouts.gateway", + "user.console_preferences.dashboard_layouts.organization", + "user.console_preferences.dashboard_layouts.overview", + "user.console_preferences.dashboard_layouts.user", + "user.console_preferences.sort_by", + "user.console_preferences.sort_by.api_key", + "user.console_preferences.sort_by.application", + "user.console_preferences.sort_by.collaborator", + "user.console_preferences.sort_by.end_device", + "user.console_preferences.sort_by.gateway", + "user.console_preferences.sort_by.organization", + "user.console_preferences.sort_by.user", "user.contact_info", "user.created_at", "user.deleted_at", @@ -126,6 +191,25 @@ var UpdateUserRequestFieldPathsNested = []string{ "user", "user.admin", "user.attributes", + "user.console_preferences", + "user.console_preferences.console_theme", + "user.console_preferences.dashboard_layouts", + "user.console_preferences.dashboard_layouts.api_key", + "user.console_preferences.dashboard_layouts.application", + "user.console_preferences.dashboard_layouts.collaborator", + "user.console_preferences.dashboard_layouts.end_device", + "user.console_preferences.dashboard_layouts.gateway", + "user.console_preferences.dashboard_layouts.organization", + "user.console_preferences.dashboard_layouts.overview", + "user.console_preferences.dashboard_layouts.user", + "user.console_preferences.sort_by", + "user.console_preferences.sort_by.api_key", + "user.console_preferences.sort_by.application", + "user.console_preferences.sort_by.collaborator", + "user.console_preferences.sort_by.end_device", + "user.console_preferences.sort_by.gateway", + "user.console_preferences.sort_by.organization", + "user.console_preferences.sort_by.user", "user.contact_info", "user.created_at", "user.deleted_at", @@ -392,3 +476,43 @@ var CreateLoginTokenResponseFieldPathsNested = []string{ var CreateLoginTokenResponseFieldPathsTopLevel = []string{ "token", } +var UserConsolePreferences_DashboardLayoutsFieldPathsNested = []string{ + "api_key", + "application", + "collaborator", + "end_device", + "gateway", + "organization", + "overview", + "user", +} + +var UserConsolePreferences_DashboardLayoutsFieldPathsTopLevel = []string{ + "api_key", + "application", + "collaborator", + "end_device", + "gateway", + "organization", + "overview", + "user", +} +var UserConsolePreferences_SortByFieldPathsNested = []string{ + "api_key", + "application", + "collaborator", + "end_device", + "gateway", + "organization", + "user", +} + +var UserConsolePreferences_SortByFieldPathsTopLevel = []string{ + "api_key", + "application", + "collaborator", + "end_device", + "gateway", + "organization", + "user", +} diff --git a/pkg/ttnpb/user.pb.setters.fm.go b/pkg/ttnpb/user.pb.setters.fm.go index 667ebc4ca7..8b641af585 100644 --- a/pkg/ttnpb/user.pb.setters.fm.go +++ b/pkg/ttnpb/user.pb.setters.fm.go @@ -4,6 +4,76 @@ package ttnpb import fmt "fmt" +func (dst *UserConsolePreferences) SetFields(src *UserConsolePreferences, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "console_theme": + if len(subs) > 0 { + return fmt.Errorf("'console_theme' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.ConsoleTheme = src.ConsoleTheme + } else { + dst.ConsoleTheme = 0 + } + case "dashboard_layouts": + if len(subs) > 0 { + var newDst, newSrc *UserConsolePreferences_DashboardLayouts + if (src == nil || src.DashboardLayouts == nil) && dst.DashboardLayouts == nil { + continue + } + if src != nil { + newSrc = src.DashboardLayouts + } + if dst.DashboardLayouts != nil { + newDst = dst.DashboardLayouts + } else { + newDst = &UserConsolePreferences_DashboardLayouts{} + dst.DashboardLayouts = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.DashboardLayouts = src.DashboardLayouts + } else { + dst.DashboardLayouts = nil + } + } + case "sort_by": + if len(subs) > 0 { + var newDst, newSrc *UserConsolePreferences_SortBy + if (src == nil || src.SortBy == nil) && dst.SortBy == nil { + continue + } + if src != nil { + newSrc = src.SortBy + } + if dst.SortBy != nil { + newDst = dst.SortBy + } else { + newDst = &UserConsolePreferences_SortBy{} + dst.SortBy = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.SortBy = src.SortBy + } else { + dst.SortBy = nil + } + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + func (dst *User) SetFields(src *User, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { @@ -227,6 +297,31 @@ func (dst *User) SetFields(src *User, paths ...string) error { dst.ProfilePicture = nil } } + case "console_preferences": + if len(subs) > 0 { + var newDst, newSrc *UserConsolePreferences + if (src == nil || src.ConsolePreferences == nil) && dst.ConsolePreferences == nil { + continue + } + if src != nil { + newSrc = src.ConsolePreferences + } + if dst.ConsolePreferences != nil { + newDst = dst.ConsolePreferences + } else { + newDst = &UserConsolePreferences{} + dst.ConsolePreferences = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.ConsolePreferences = src.ConsolePreferences + } else { + dst.ConsolePreferences = nil + } + } default: return fmt.Errorf("invalid field: '%s'", name) @@ -1394,3 +1489,167 @@ func (dst *CreateLoginTokenResponse) SetFields(src *CreateLoginTokenResponse, pa } return nil } + +func (dst *UserConsolePreferences_DashboardLayouts) SetFields(src *UserConsolePreferences_DashboardLayouts, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "api_key": + if len(subs) > 0 { + return fmt.Errorf("'api_key' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.ApiKey = src.ApiKey + } else { + dst.ApiKey = 0 + } + case "application": + if len(subs) > 0 { + return fmt.Errorf("'application' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Application = src.Application + } else { + dst.Application = 0 + } + case "collaborator": + if len(subs) > 0 { + return fmt.Errorf("'collaborator' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Collaborator = src.Collaborator + } else { + dst.Collaborator = 0 + } + case "end_device": + if len(subs) > 0 { + return fmt.Errorf("'end_device' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.EndDevice = src.EndDevice + } else { + dst.EndDevice = 0 + } + case "gateway": + if len(subs) > 0 { + return fmt.Errorf("'gateway' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Gateway = src.Gateway + } else { + dst.Gateway = 0 + } + case "organization": + if len(subs) > 0 { + return fmt.Errorf("'organization' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Organization = src.Organization + } else { + dst.Organization = 0 + } + case "overview": + if len(subs) > 0 { + return fmt.Errorf("'overview' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Overview = src.Overview + } else { + dst.Overview = 0 + } + case "user": + if len(subs) > 0 { + return fmt.Errorf("'user' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.User = src.User + } else { + dst.User = 0 + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *UserConsolePreferences_SortBy) SetFields(src *UserConsolePreferences_SortBy, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "api_key": + if len(subs) > 0 { + return fmt.Errorf("'api_key' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.ApiKey = src.ApiKey + } else { + var zero string + dst.ApiKey = zero + } + case "application": + if len(subs) > 0 { + return fmt.Errorf("'application' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Application = src.Application + } else { + var zero string + dst.Application = zero + } + case "collaborator": + if len(subs) > 0 { + return fmt.Errorf("'collaborator' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Collaborator = src.Collaborator + } else { + var zero string + dst.Collaborator = zero + } + case "end_device": + if len(subs) > 0 { + return fmt.Errorf("'end_device' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.EndDevice = src.EndDevice + } else { + var zero string + dst.EndDevice = zero + } + case "gateway": + if len(subs) > 0 { + return fmt.Errorf("'gateway' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Gateway = src.Gateway + } else { + var zero string + dst.Gateway = zero + } + case "organization": + if len(subs) > 0 { + return fmt.Errorf("'organization' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Organization = src.Organization + } else { + var zero string + dst.Organization = zero + } + case "user": + if len(subs) > 0 { + return fmt.Errorf("'user' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.User = src.User + } else { + var zero string + dst.User = zero + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} diff --git a/pkg/ttnpb/user.pb.validate.go b/pkg/ttnpb/user.pb.validate.go index cafc16edf6..5ca71d7eaf 100644 --- a/pkg/ttnpb/user.pb.validate.go +++ b/pkg/ttnpb/user.pb.validate.go @@ -32,6 +32,113 @@ var ( _ = anypb.Any{} ) +// ValidateFields checks the field values on UserConsolePreferences with the +// rules defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *UserConsolePreferences) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = UserConsolePreferencesFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "console_theme": + // no validation rules for ConsoleTheme + case "dashboard_layouts": + + if v, ok := interface{}(m.GetDashboardLayouts()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return UserConsolePreferencesValidationError{ + field: "dashboard_layouts", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "sort_by": + + if v, ok := interface{}(m.GetSortBy()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return UserConsolePreferencesValidationError{ + field: "sort_by", + reason: "embedded message failed validation", + cause: err, + } + } + } + + default: + return UserConsolePreferencesValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// UserConsolePreferencesValidationError is the validation error returned by +// UserConsolePreferences.ValidateFields if the designated constraints aren't met. +type UserConsolePreferencesValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e UserConsolePreferencesValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e UserConsolePreferencesValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e UserConsolePreferencesValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e UserConsolePreferencesValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e UserConsolePreferencesValidationError) ErrorName() string { + return "UserConsolePreferencesValidationError" +} + +// Error satisfies the builtin error interface +func (e UserConsolePreferencesValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sUserConsolePreferences.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = UserConsolePreferencesValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = UserConsolePreferencesValidationError{} + // ValidateFields checks the field values on User with the rules defined in the // proto definition for this message. If any rules are violated, an error is returned. func (m *User) ValidateFields(paths ...string) error { @@ -288,6 +395,18 @@ func (m *User) ValidateFields(paths ...string) error { } } + case "console_preferences": + + if v, ok := interface{}(m.GetConsolePreferences()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return UserValidationError{ + field: "console_preferences", + reason: "embedded message failed validation", + cause: err, + } + } + } + default: return UserValidationError{ field: name, @@ -3276,3 +3395,332 @@ var _ interface { Cause() error ErrorName() string } = CreateLoginTokenResponseValidationError{} + +// ValidateFields checks the field values on +// UserConsolePreferences_DashboardLayouts with the rules defined in the proto +// definition for this message. If any rules are violated, an error is returned. +func (m *UserConsolePreferences_DashboardLayouts) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = UserConsolePreferences_DashboardLayoutsFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "api_key": + // no validation rules for ApiKey + case "application": + // no validation rules for Application + case "collaborator": + // no validation rules for Collaborator + case "end_device": + // no validation rules for EndDevice + case "gateway": + // no validation rules for Gateway + case "organization": + // no validation rules for Organization + case "overview": + // no validation rules for Overview + case "user": + // no validation rules for User + default: + return UserConsolePreferences_DashboardLayoutsValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// UserConsolePreferences_DashboardLayoutsValidationError is the validation +// error returned by UserConsolePreferences_DashboardLayouts.ValidateFields if +// the designated constraints aren't met. +type UserConsolePreferences_DashboardLayoutsValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e UserConsolePreferences_DashboardLayoutsValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e UserConsolePreferences_DashboardLayoutsValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e UserConsolePreferences_DashboardLayoutsValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e UserConsolePreferences_DashboardLayoutsValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e UserConsolePreferences_DashboardLayoutsValidationError) ErrorName() string { + return "UserConsolePreferences_DashboardLayoutsValidationError" +} + +// Error satisfies the builtin error interface +func (e UserConsolePreferences_DashboardLayoutsValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sUserConsolePreferences_DashboardLayouts.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = UserConsolePreferences_DashboardLayoutsValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = UserConsolePreferences_DashboardLayoutsValidationError{} + +// ValidateFields checks the field values on UserConsolePreferences_SortBy with +// the rules defined in the proto definition for this message. If any rules +// are violated, an error is returned. +func (m *UserConsolePreferences_SortBy) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = UserConsolePreferences_SortByFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "api_key": + + if _, ok := _UserConsolePreferences_SortBy_ApiKey_InLookup[m.GetApiKey()]; !ok { + return UserConsolePreferences_SortByValidationError{ + field: "api_key", + reason: "value must be in list [ api_key_id -api_key_id name -name created_at -created_at expires_at -expires_at]", + } + } + + case "application": + + if _, ok := _UserConsolePreferences_SortBy_Application_InLookup[m.GetApplication()]; !ok { + return UserConsolePreferences_SortByValidationError{ + field: "application", + reason: "value must be in list [ application_id -application_id name -name created_at -created_at]", + } + } + + case "collaborator": + + if _, ok := _UserConsolePreferences_SortBy_Collaborator_InLookup[m.GetCollaborator()]; !ok { + return UserConsolePreferences_SortByValidationError{ + field: "collaborator", + reason: "value must be in list [ id -id rights -rights]", + } + } + + case "end_device": + + if _, ok := _UserConsolePreferences_SortBy_EndDevice_InLookup[m.GetEndDevice()]; !ok { + return UserConsolePreferences_SortByValidationError{ + field: "end_device", + reason: "value must be in list [ device_id -device_id join_eui -join_eui dev_eui -dev_eui name -name description -description created_at -created_at last_seen_at -last_seen_at]", + } + } + + case "gateway": + + if _, ok := _UserConsolePreferences_SortBy_Gateway_InLookup[m.GetGateway()]; !ok { + return UserConsolePreferences_SortByValidationError{ + field: "gateway", + reason: "value must be in list [ gateway_id -gateway_id gateway_eui -gateway_eui name -name created_at -created_at]", + } + } + + case "organization": + + if _, ok := _UserConsolePreferences_SortBy_Organization_InLookup[m.GetOrganization()]; !ok { + return UserConsolePreferences_SortByValidationError{ + field: "organization", + reason: "value must be in list [ organization_id -organization_id name -name created_at -created_at]", + } + } + + case "user": + + if _, ok := _UserConsolePreferences_SortBy_User_InLookup[m.GetUser()]; !ok { + return UserConsolePreferences_SortByValidationError{ + field: "user", + reason: "value must be in list [ user_id -user_id name -name primary_email_address -primary_email_address state -state admin -admin created_at -created_at]", + } + } + + default: + return UserConsolePreferences_SortByValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// UserConsolePreferences_SortByValidationError is the validation error +// returned by UserConsolePreferences_SortBy.ValidateFields if the designated +// constraints aren't met. +type UserConsolePreferences_SortByValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e UserConsolePreferences_SortByValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e UserConsolePreferences_SortByValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e UserConsolePreferences_SortByValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e UserConsolePreferences_SortByValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e UserConsolePreferences_SortByValidationError) ErrorName() string { + return "UserConsolePreferences_SortByValidationError" +} + +// Error satisfies the builtin error interface +func (e UserConsolePreferences_SortByValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sUserConsolePreferences_SortBy.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = UserConsolePreferences_SortByValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = UserConsolePreferences_SortByValidationError{} + +var _UserConsolePreferences_SortBy_ApiKey_InLookup = map[string]struct{}{ + "": {}, + "api_key_id": {}, + "-api_key_id": {}, + "name": {}, + "-name": {}, + "created_at": {}, + "-created_at": {}, + "expires_at": {}, + "-expires_at": {}, +} + +var _UserConsolePreferences_SortBy_Application_InLookup = map[string]struct{}{ + "": {}, + "application_id": {}, + "-application_id": {}, + "name": {}, + "-name": {}, + "created_at": {}, + "-created_at": {}, +} + +var _UserConsolePreferences_SortBy_Collaborator_InLookup = map[string]struct{}{ + "": {}, + "id": {}, + "-id": {}, + "rights": {}, + "-rights": {}, +} + +var _UserConsolePreferences_SortBy_EndDevice_InLookup = map[string]struct{}{ + "": {}, + "device_id": {}, + "-device_id": {}, + "join_eui": {}, + "-join_eui": {}, + "dev_eui": {}, + "-dev_eui": {}, + "name": {}, + "-name": {}, + "description": {}, + "-description": {}, + "created_at": {}, + "-created_at": {}, + "last_seen_at": {}, + "-last_seen_at": {}, +} + +var _UserConsolePreferences_SortBy_Gateway_InLookup = map[string]struct{}{ + "": {}, + "gateway_id": {}, + "-gateway_id": {}, + "gateway_eui": {}, + "-gateway_eui": {}, + "name": {}, + "-name": {}, + "created_at": {}, + "-created_at": {}, +} + +var _UserConsolePreferences_SortBy_Organization_InLookup = map[string]struct{}{ + "": {}, + "organization_id": {}, + "-organization_id": {}, + "name": {}, + "-name": {}, + "created_at": {}, + "-created_at": {}, +} + +var _UserConsolePreferences_SortBy_User_InLookup = map[string]struct{}{ + "": {}, + "user_id": {}, + "-user_id": {}, + "name": {}, + "-name": {}, + "primary_email_address": {}, + "-primary_email_address": {}, + "state": {}, + "-state": {}, + "admin": {}, + "-admin": {}, + "created_at": {}, + "-created_at": {}, +} diff --git a/pkg/ttnpb/user_flags.pb.go b/pkg/ttnpb/user_flags.pb.go index eaec14bbea..aae501259e 100644 --- a/pkg/ttnpb/user_flags.pb.go +++ b/pkg/ttnpb/user_flags.pb.go @@ -12,6 +12,61 @@ import ( pflag "github.com/spf13/pflag" ) +// AddSelectFlagsForUserConsolePreferences adds flags to select fields in UserConsolePreferences. +func AddSelectFlagsForUserConsolePreferences(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("console-theme", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("console-theme", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("dashboard-layouts", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("dashboard-layouts", prefix), true), flagsplugin.WithHidden(hidden))) + // NOTE: dashboard_layouts (UserConsolePreferences_DashboardLayouts) does not seem to have select flags. + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("sort-by", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("sort-by", prefix), true), flagsplugin.WithHidden(hidden))) + // NOTE: sort_by (UserConsolePreferences_SortBy) does not seem to have select flags. +} + +// SelectFromFlags outputs the fieldmask paths forUserConsolePreferences message from select flags. +func PathsFromSelectFlagsForUserConsolePreferences(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("console_theme", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("console_theme", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("dashboard_layouts", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("dashboard_layouts", prefix)) + } + // NOTE: dashboard_layouts (UserConsolePreferences_DashboardLayouts) does not seem to have select flags. + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("sort_by", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("sort_by", prefix)) + } + // NOTE: sort_by (UserConsolePreferences_SortBy) does not seem to have select flags. + return paths, nil +} + +// AddSetFlagsForUserConsolePreferences adds flags to select fields in UserConsolePreferences. +func AddSetFlagsForUserConsolePreferences(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("console-theme", prefix), flagsplugin.EnumValueDesc(ConsoleTheme_value), flagsplugin.WithHidden(hidden))) + // FIXME: Skipping DashboardLayouts because it does not seem to implement AddSetFlags. + // FIXME: Skipping SortBy because it does not seem to implement AddSetFlags. +} + +// SetFromFlags sets the UserConsolePreferences message from flags. +func (m *UserConsolePreferences) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("console_theme", prefix)); err != nil { + return nil, err + } else if changed { + enumValue, err := flagsplugin.SetEnumString(val, ConsoleTheme_value) + if err != nil { + return nil, err + } + m.ConsoleTheme = ConsoleTheme(enumValue) + paths = append(paths, flagsplugin.Prefix("console_theme", prefix)) + } + // FIXME: Skipping DashboardLayouts because it does not seem to implement AddSetFlags. + // FIXME: Skipping SortBy because it does not seem to implement AddSetFlags. + return paths, nil +} + // AddSelectFlagsForUser adds flags to select fields in User. func AddSelectFlagsForUser(flags *pflag.FlagSet, prefix string, hidden bool) { flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("deleted-at", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("deleted-at", prefix), false), flagsplugin.WithHidden(hidden))) @@ -32,6 +87,8 @@ func AddSelectFlagsForUser(flags *pflag.FlagSet, prefix string, hidden bool) { flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("temporary-password-expires-at", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("temporary-password-expires-at", prefix), false), flagsplugin.WithHidden(hidden))) flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("profile-picture", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("profile-picture", prefix), true), flagsplugin.WithHidden(hidden))) // NOTE: profile_picture (Picture) does not seem to have select flags. + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("console-preferences", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("console-preferences", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForUserConsolePreferences(flags, flagsplugin.Prefix("console-preferences", prefix), hidden) } // SelectFromFlags outputs the fieldmask paths forUser message from select flags. @@ -122,6 +179,16 @@ func PathsFromSelectFlagsForUser(flags *pflag.FlagSet, prefix string) (paths []s paths = append(paths, flagsplugin.Prefix("profile_picture", prefix)) } // NOTE: profile_picture (Picture) does not seem to have select flags. + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("console_preferences", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("console_preferences", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForUserConsolePreferences(flags, flagsplugin.Prefix("console_preferences", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } return paths, nil } @@ -141,6 +208,7 @@ func AddSetFlagsForUser(flags *pflag.FlagSet, prefix string, hidden bool) { flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("admin", prefix), "", flagsplugin.WithHidden(hidden))) flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("temporary-password", prefix), "", flagsplugin.WithHidden(hidden))) // FIXME: Skipping ProfilePicture because it does not seem to implement AddSetFlags. + AddSetFlagsForUserConsolePreferences(flags, flagsplugin.Prefix("console-preferences", prefix), hidden) } // SetFromFlags sets the User message from flags. @@ -227,6 +295,16 @@ func (m *User) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string paths = append(paths, flagsplugin.Prefix("temporary_password", prefix)) } // FIXME: Skipping ProfilePicture because it does not seem to implement AddSetFlags. + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("console_preferences", prefix)); changed { + if m.ConsolePreferences == nil { + m.ConsolePreferences = &UserConsolePreferences{} + } + if setPaths, err := m.ConsolePreferences.SetFromFlags(flags, flagsplugin.Prefix("console_preferences", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } return paths, nil } diff --git a/pkg/ttnpb/user_json.pb.go b/pkg/ttnpb/user_json.pb.go index adc00c94ae..da8bfc947e 100644 --- a/pkg/ttnpb/user_json.pb.go +++ b/pkg/ttnpb/user_json.pb.go @@ -11,6 +11,268 @@ import ( jsonplugin "github.com/TheThingsIndustries/protoc-gen-go-json/jsonplugin" ) +// MarshalProtoJSON marshals the ConsoleTheme to JSON. +func (x ConsoleTheme) MarshalProtoJSON(s *jsonplugin.MarshalState) { + s.WriteEnumString(int32(x), ConsoleTheme_name) +} + +// MarshalText marshals the ConsoleTheme to text. +func (x ConsoleTheme) MarshalText() ([]byte, error) { + return []byte(jsonplugin.GetEnumString(int32(x), ConsoleTheme_name)), nil +} + +// MarshalJSON marshals the ConsoleTheme to JSON. +func (x ConsoleTheme) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// ConsoleTheme_customvalue contains custom string values that extend ConsoleTheme_value. +var ConsoleTheme_customvalue = map[string]int32{ + "SYSTEM": 0, + "LIGHT": 1, + "DARK": 2, +} + +// UnmarshalProtoJSON unmarshals the ConsoleTheme from JSON. +func (x *ConsoleTheme) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + v := s.ReadEnum(ConsoleTheme_value, ConsoleTheme_customvalue) + if err := s.Err(); err != nil { + s.SetErrorf("could not read ConsoleTheme enum: %v", err) + return + } + *x = ConsoleTheme(v) +} + +// UnmarshalText unmarshals the ConsoleTheme from text. +func (x *ConsoleTheme) UnmarshalText(b []byte) error { + i, err := jsonplugin.ParseEnumString(string(b), ConsoleTheme_customvalue, ConsoleTheme_value) + if err != nil { + return err + } + *x = ConsoleTheme(i) + return nil +} + +// UnmarshalJSON unmarshals the ConsoleTheme from JSON. +func (x *ConsoleTheme) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the DashboardLayout to JSON. +func (x DashboardLayout) MarshalProtoJSON(s *jsonplugin.MarshalState) { + s.WriteEnumString(int32(x), DashboardLayout_name) +} + +// MarshalText marshals the DashboardLayout to text. +func (x DashboardLayout) MarshalText() ([]byte, error) { + return []byte(jsonplugin.GetEnumString(int32(x), DashboardLayout_name)), nil +} + +// MarshalJSON marshals the DashboardLayout to JSON. +func (x DashboardLayout) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// DashboardLayout_customvalue contains custom string values that extend DashboardLayout_value. +var DashboardLayout_customvalue = map[string]int32{ + "TABLE": 0, + "LIST": 1, + "GRID": 2, +} + +// UnmarshalProtoJSON unmarshals the DashboardLayout from JSON. +func (x *DashboardLayout) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + v := s.ReadEnum(DashboardLayout_value, DashboardLayout_customvalue) + if err := s.Err(); err != nil { + s.SetErrorf("could not read DashboardLayout enum: %v", err) + return + } + *x = DashboardLayout(v) +} + +// UnmarshalText unmarshals the DashboardLayout from text. +func (x *DashboardLayout) UnmarshalText(b []byte) error { + i, err := jsonplugin.ParseEnumString(string(b), DashboardLayout_customvalue, DashboardLayout_value) + if err != nil { + return err + } + *x = DashboardLayout(i) + return nil +} + +// UnmarshalJSON unmarshals the DashboardLayout from JSON. +func (x *DashboardLayout) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the UserConsolePreferences_DashboardLayouts message to JSON. +func (x *UserConsolePreferences_DashboardLayouts) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.ApiKey != 0 || s.HasField("api_key") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("api_key") + x.ApiKey.MarshalProtoJSON(s) + } + if x.Application != 0 || s.HasField("application") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("application") + x.Application.MarshalProtoJSON(s) + } + if x.Collaborator != 0 || s.HasField("collaborator") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("collaborator") + x.Collaborator.MarshalProtoJSON(s) + } + if x.EndDevice != 0 || s.HasField("end_device") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("end_device") + x.EndDevice.MarshalProtoJSON(s) + } + if x.Gateway != 0 || s.HasField("gateway") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("gateway") + x.Gateway.MarshalProtoJSON(s) + } + if x.Organization != 0 || s.HasField("organization") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("organization") + x.Organization.MarshalProtoJSON(s) + } + if x.Overview != 0 || s.HasField("overview") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("overview") + x.Overview.MarshalProtoJSON(s) + } + if x.User != 0 || s.HasField("user") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("user") + x.User.MarshalProtoJSON(s) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the UserConsolePreferences_DashboardLayouts to JSON. +func (x *UserConsolePreferences_DashboardLayouts) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the UserConsolePreferences_DashboardLayouts message from JSON. +func (x *UserConsolePreferences_DashboardLayouts) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "api_key", "apiKey": + s.AddField("api_key") + x.ApiKey.UnmarshalProtoJSON(s) + case "application": + s.AddField("application") + x.Application.UnmarshalProtoJSON(s) + case "collaborator": + s.AddField("collaborator") + x.Collaborator.UnmarshalProtoJSON(s) + case "end_device", "endDevice": + s.AddField("end_device") + x.EndDevice.UnmarshalProtoJSON(s) + case "gateway": + s.AddField("gateway") + x.Gateway.UnmarshalProtoJSON(s) + case "organization": + s.AddField("organization") + x.Organization.UnmarshalProtoJSON(s) + case "overview": + s.AddField("overview") + x.Overview.UnmarshalProtoJSON(s) + case "user": + s.AddField("user") + x.User.UnmarshalProtoJSON(s) + } + }) +} + +// UnmarshalJSON unmarshals the UserConsolePreferences_DashboardLayouts from JSON. +func (x *UserConsolePreferences_DashboardLayouts) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the UserConsolePreferences message to JSON. +func (x *UserConsolePreferences) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.ConsoleTheme != 0 || s.HasField("console_theme") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("console_theme") + x.ConsoleTheme.MarshalProtoJSON(s) + } + if x.DashboardLayouts != nil || s.HasField("dashboard_layouts") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("dashboard_layouts") + x.DashboardLayouts.MarshalProtoJSON(s.WithField("dashboard_layouts")) + } + if x.SortBy != nil || s.HasField("sort_by") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("sort_by") + // NOTE: UserConsolePreferences_SortBy does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, x.SortBy) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the UserConsolePreferences to JSON. +func (x *UserConsolePreferences) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the UserConsolePreferences message from JSON. +func (x *UserConsolePreferences) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "console_theme", "consoleTheme": + s.AddField("console_theme") + x.ConsoleTheme.UnmarshalProtoJSON(s) + case "dashboard_layouts", "dashboardLayouts": + if s.ReadNil() { + x.DashboardLayouts = nil + return + } + x.DashboardLayouts = &UserConsolePreferences_DashboardLayouts{} + x.DashboardLayouts.UnmarshalProtoJSON(s.WithField("dashboard_layouts", true)) + case "sort_by", "sortBy": + s.AddField("sort_by") + if s.ReadNil() { + x.SortBy = nil + return + } + // NOTE: UserConsolePreferences_SortBy does not seem to implement UnmarshalProtoJSON. + var v UserConsolePreferences_SortBy + golang.UnmarshalMessage(s, &v) + x.SortBy = &v + } + }) +} + +// UnmarshalJSON unmarshals the UserConsolePreferences from JSON. +func (x *UserConsolePreferences) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + // MarshalProtoJSON marshals the User message to JSON. func (x *User) MarshalProtoJSON(s *jsonplugin.MarshalState) { if x == nil { @@ -162,6 +424,11 @@ func (x *User) MarshalProtoJSON(s *jsonplugin.MarshalState) { // NOTE: Picture does not seem to implement MarshalProtoJSON. golang.MarshalMessage(s, x.ProfilePicture) } + if x.ConsolePreferences != nil || s.HasField("console_preferences") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("console_preferences") + x.ConsolePreferences.MarshalProtoJSON(s.WithField("console_preferences")) + } s.WriteObjectEnd() } @@ -331,6 +598,13 @@ func (x *User) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { var v Picture golang.UnmarshalMessage(s, &v) x.ProfilePicture = &v + case "console_preferences", "consolePreferences": + if s.ReadNil() { + x.ConsolePreferences = nil + return + } + x.ConsolePreferences = &UserConsolePreferences{} + x.ConsolePreferences.UnmarshalProtoJSON(s.WithField("console_preferences", true)) } }) } diff --git a/sdk/js/generated/api-definition.json b/sdk/js/generated/api-definition.json index 74162f9b84..2473717de6 100644 --- a/sdk/js/generated/api-definition.json +++ b/sdk/js/generated/api-definition.json @@ -6894,6 +6894,25 @@ "allowedFieldMaskPaths": [ "admin", "attributes", + "console_preferences", + "console_preferences.console_theme", + "console_preferences.dashboard_layouts", + "console_preferences.dashboard_layouts.api_key", + "console_preferences.dashboard_layouts.application", + "console_preferences.dashboard_layouts.collaborator", + "console_preferences.dashboard_layouts.end_device", + "console_preferences.dashboard_layouts.gateway", + "console_preferences.dashboard_layouts.organization", + "console_preferences.dashboard_layouts.overview", + "console_preferences.dashboard_layouts.user", + "console_preferences.sort_by", + "console_preferences.sort_by.api_key", + "console_preferences.sort_by.application", + "console_preferences.sort_by.collaborator", + "console_preferences.sort_by.end_device", + "console_preferences.sort_by.gateway", + "console_preferences.sort_by.organization", + "console_preferences.sort_by.user", "contact_info", "created_at", "deleted_at", @@ -7116,6 +7135,25 @@ "allowedFieldMaskPaths": [ "admin", "attributes", + "console_preferences", + "console_preferences.console_theme", + "console_preferences.dashboard_layouts", + "console_preferences.dashboard_layouts.api_key", + "console_preferences.dashboard_layouts.application", + "console_preferences.dashboard_layouts.collaborator", + "console_preferences.dashboard_layouts.end_device", + "console_preferences.dashboard_layouts.gateway", + "console_preferences.dashboard_layouts.organization", + "console_preferences.dashboard_layouts.overview", + "console_preferences.dashboard_layouts.user", + "console_preferences.sort_by", + "console_preferences.sort_by.api_key", + "console_preferences.sort_by.application", + "console_preferences.sort_by.collaborator", + "console_preferences.sort_by.end_device", + "console_preferences.sort_by.gateway", + "console_preferences.sort_by.organization", + "console_preferences.sort_by.user", "contact_info", "created_at", "deleted_at", @@ -7152,6 +7190,25 @@ "allowedFieldMaskPaths": [ "admin", "attributes", + "console_preferences", + "console_preferences.console_theme", + "console_preferences.dashboard_layouts", + "console_preferences.dashboard_layouts.api_key", + "console_preferences.dashboard_layouts.application", + "console_preferences.dashboard_layouts.collaborator", + "console_preferences.dashboard_layouts.end_device", + "console_preferences.dashboard_layouts.gateway", + "console_preferences.dashboard_layouts.organization", + "console_preferences.dashboard_layouts.overview", + "console_preferences.dashboard_layouts.user", + "console_preferences.sort_by", + "console_preferences.sort_by.api_key", + "console_preferences.sort_by.application", + "console_preferences.sort_by.collaborator", + "console_preferences.sort_by.end_device", + "console_preferences.sort_by.gateway", + "console_preferences.sort_by.organization", + "console_preferences.sort_by.user", "contact_info", "created_at", "deleted_at", @@ -7191,6 +7248,25 @@ "allowedFieldMaskPaths": [ "admin", "attributes", + "console_preferences", + "console_preferences.console_theme", + "console_preferences.dashboard_layouts", + "console_preferences.dashboard_layouts.api_key", + "console_preferences.dashboard_layouts.application", + "console_preferences.dashboard_layouts.collaborator", + "console_preferences.dashboard_layouts.end_device", + "console_preferences.dashboard_layouts.gateway", + "console_preferences.dashboard_layouts.organization", + "console_preferences.dashboard_layouts.overview", + "console_preferences.dashboard_layouts.user", + "console_preferences.sort_by", + "console_preferences.sort_by.api_key", + "console_preferences.sort_by.application", + "console_preferences.sort_by.collaborator", + "console_preferences.sort_by.end_device", + "console_preferences.sort_by.gateway", + "console_preferences.sort_by.organization", + "console_preferences.sort_by.user", "contact_info", "created_at", "deleted_at", diff --git a/sdk/js/generated/api.json b/sdk/js/generated/api.json index 36333ebb9e..00e833cff9 100644 --- a/sdk/js/generated/api.json +++ b/sdk/js/generated/api.json @@ -49155,11 +49155,58 @@ "name": "ttn/lorawan/v3/user.proto", "description": "", "package": "ttn.lorawan.v3", - "hasEnums": false, + "hasEnums": true, "hasExtensions": false, "hasMessages": true, "hasServices": false, - "enums": [], + "enums": [ + { + "name": "ConsoleTheme", + "longName": "ConsoleTheme", + "fullName": "ttn.lorawan.v3.ConsoleTheme", + "description": "ConsoleTheme is the theme of the Console.", + "values": [ + { + "name": "CONSOLE_THEME_SYSTEM", + "number": "0", + "description": "The user prefers the system mode." + }, + { + "name": "CONSOLE_THEME_LIGHT", + "number": "1", + "description": "The user prefers the light mode." + }, + { + "name": "CONSOLE_THEME_DARK", + "number": "2", + "description": "The user prefers the dark mode." + } + ] + }, + { + "name": "DashboardLayout", + "longName": "DashboardLayout", + "fullName": "ttn.lorawan.v3.DashboardLayout", + "description": "DashboardLayout is a set of possible layout values to be used in the Console.", + "values": [ + { + "name": "DASHBOARD_LAYOUT_TABLE", + "number": "0", + "description": "" + }, + { + "name": "DASHBOARD_LAYOUT_LIST", + "number": "1", + "description": "" + }, + { + "name": "DASHBOARD_LAYOUT_GRID", + "number": "2", + "description": "" + } + ] + } + ], "extensions": [], "messages": [ { @@ -50684,6 +50731,18 @@ "isoneof": false, "oneofdecl": "", "defaultValue": "" + }, + { + "name": "console_preferences", + "description": "Console preferences contains the user's preferences regarding the behavior of the Console.", + "label": "", + "type": "UserConsolePreferences", + "longType": "UserConsolePreferences", + "fullType": "ttn.lorawan.v3.UserConsolePreferences", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" } ] }, @@ -50723,6 +50782,386 @@ } ] }, + { + "name": "UserConsolePreferences", + "longName": "UserConsolePreferences", + "fullName": "ttn.lorawan.v3.UserConsolePreferences", + "description": "UserConsolePreferences is the message that defines the user preferences for the Console.", + "hasExtensions": false, + "hasFields": true, + "hasOneofs": false, + "extensions": [], + "fields": [ + { + "name": "console_theme", + "description": "", + "label": "", + "type": "ConsoleTheme", + "longType": "ConsoleTheme", + "fullType": "ttn.lorawan.v3.ConsoleTheme", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "dashboard_layouts", + "description": "", + "label": "", + "type": "DashboardLayouts", + "longType": "UserConsolePreferences.DashboardLayouts", + "fullType": "ttn.lorawan.v3.UserConsolePreferences.DashboardLayouts", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "sort_by", + "description": "", + "label": "", + "type": "SortBy", + "longType": "UserConsolePreferences.SortBy", + "fullType": "ttn.lorawan.v3.UserConsolePreferences.SortBy", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + } + ] + }, + { + "name": "DashboardLayouts", + "longName": "UserConsolePreferences.DashboardLayouts", + "fullName": "ttn.lorawan.v3.UserConsolePreferences.DashboardLayouts", + "description": "", + "hasExtensions": false, + "hasFields": true, + "hasOneofs": false, + "extensions": [], + "fields": [ + { + "name": "api_key", + "description": "", + "label": "", + "type": "DashboardLayout", + "longType": "DashboardLayout", + "fullType": "ttn.lorawan.v3.DashboardLayout", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "application", + "description": "", + "label": "", + "type": "DashboardLayout", + "longType": "DashboardLayout", + "fullType": "ttn.lorawan.v3.DashboardLayout", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "collaborator", + "description": "", + "label": "", + "type": "DashboardLayout", + "longType": "DashboardLayout", + "fullType": "ttn.lorawan.v3.DashboardLayout", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "end_device", + "description": "", + "label": "", + "type": "DashboardLayout", + "longType": "DashboardLayout", + "fullType": "ttn.lorawan.v3.DashboardLayout", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "gateway", + "description": "", + "label": "", + "type": "DashboardLayout", + "longType": "DashboardLayout", + "fullType": "ttn.lorawan.v3.DashboardLayout", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "organization", + "description": "", + "label": "", + "type": "DashboardLayout", + "longType": "DashboardLayout", + "fullType": "ttn.lorawan.v3.DashboardLayout", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "overview", + "description": "", + "label": "", + "type": "DashboardLayout", + "longType": "DashboardLayout", + "fullType": "ttn.lorawan.v3.DashboardLayout", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + }, + { + "name": "user", + "description": "", + "label": "", + "type": "DashboardLayout", + "longType": "DashboardLayout", + "fullType": "ttn.lorawan.v3.DashboardLayout", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "" + } + ] + }, + { + "name": "SortBy", + "longName": "UserConsolePreferences.SortBy", + "fullName": "ttn.lorawan.v3.UserConsolePreferences.SortBy", + "description": "SortBy defines the field to which the Console will sort the display of entities.", + "hasExtensions": false, + "hasFields": true, + "hasOneofs": false, + "extensions": [], + "fields": [ + { + "name": "api_key", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "", + "options": { + "validate.rules": [ + { + "name": "string.in", + "value": [ + "", + "api_key_id", + "-api_key_id", + "name", + "-name", + "created_at", + "-created_at", + "expires_at", + "-expires_at" + ] + } + ] + } + }, + { + "name": "application", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "", + "options": { + "validate.rules": [ + { + "name": "string.in", + "value": [ + "", + "application_id", + "-application_id", + "name", + "-name", + "created_at", + "-created_at" + ] + } + ] + } + }, + { + "name": "collaborator", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "", + "options": { + "validate.rules": [ + { + "name": "string.in", + "value": [ + "", + "id", + "-id", + "rights", + "-rights" + ] + } + ] + } + }, + { + "name": "end_device", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "", + "options": { + "validate.rules": [ + { + "name": "string.in", + "value": [ + "", + "device_id", + "-device_id", + "join_eui", + "-join_eui", + "dev_eui", + "-dev_eui", + "name", + "-name", + "description", + "-description", + "created_at", + "-created_at", + "last_seen_at", + "-last_seen_at" + ] + } + ] + } + }, + { + "name": "gateway", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "", + "options": { + "validate.rules": [ + { + "name": "string.in", + "value": [ + "", + "gateway_id", + "-gateway_id", + "gateway_eui", + "-gateway_eui", + "name", + "-name", + "created_at", + "-created_at" + ] + } + ] + } + }, + { + "name": "organization", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "", + "options": { + "validate.rules": [ + { + "name": "string.in", + "value": [ + "", + "organization_id", + "-organization_id", + "name", + "-name", + "created_at", + "-created_at" + ] + } + ] + } + }, + { + "name": "user", + "description": "", + "label": "", + "type": "string", + "longType": "string", + "fullType": "string", + "ismap": false, + "isoneof": false, + "oneofdecl": "", + "defaultValue": "", + "options": { + "validate.rules": [ + { + "name": "string.in", + "value": [ + "", + "user_id", + "-user_id", + "name", + "-name", + "primary_email_address", + "-primary_email_address", + "state", + "-state", + "admin", + "-admin", + "created_at", + "-created_at" + ] + } + ] + } + } + ] + }, { "name": "UserSession", "longName": "UserSession", From 16ca0d08420413993d306c1c12b9e2a2d88556bc Mon Sep 17 00:00:00 2001 From: Nicholas Cristofaro Date: Thu, 4 Jan 2024 16:18:25 +0000 Subject: [PATCH 3/5] is: Add console_preferences field to user store --- pkg/identityserver/bunstore/user_store.go | 57 +++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/pkg/identityserver/bunstore/user_store.go b/pkg/identityserver/bunstore/user_store.go index cbe10fcd4d..f66d34ef40 100644 --- a/pkg/identityserver/bunstore/user_store.go +++ b/pkg/identityserver/bunstore/user_store.go @@ -16,6 +16,7 @@ package store import ( "context" + "encoding/json" "fmt" "time" @@ -24,6 +25,7 @@ import ( "go.opentelemetry.io/otel/trace" "go.thethings.network/lorawan-stack/v3/pkg/errors" "go.thethings.network/lorawan-stack/v3/pkg/identityserver/store" + "go.thethings.network/lorawan-stack/v3/pkg/jsonpb" "go.thethings.network/lorawan-stack/v3/pkg/telemetry/tracing/tracer" "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" storeutil "go.thethings.network/lorawan-stack/v3/pkg/util/store" @@ -62,6 +64,8 @@ type User struct { ProfilePictureID *string `bun:"profile_picture_id"` ProfilePicture *Picture `bun:"rel:belongs-to,join:profile_picture_id=id"` + + ConsolePreferences json.RawMessage `bun:"console_preferences"` } // BeforeAppendModel is a hook that modifies the model on SELECT and UPDATE queries. @@ -100,6 +104,8 @@ func userToPB(m *User, fieldMask ...string) (*ttnpb.User, error) { TemporaryPassword: m.TemporaryPassword, TemporaryPasswordCreatedAt: ttnpb.ProtoTime(m.TemporaryPasswordCreatedAt), TemporaryPasswordExpiresAt: ttnpb.ProtoTime(m.TemporaryPasswordExpiresAt), + + ConsolePreferences: &ttnpb.UserConsolePreferences{}, } if len(m.Attributes) > 0 { @@ -117,6 +123,12 @@ func userToPB(m *User, fieldMask ...string) (*ttnpb.User, error) { pb.ProfilePicture = picture } + if len(m.ConsolePreferences) > 0 { + if err := jsonpb.TTN().Unmarshal(m.ConsolePreferences, pb.ConsolePreferences); err != nil { + return nil, err + } + } + if len(fieldMask) == 0 { return pb, nil } @@ -187,6 +199,14 @@ func (s *userStore) CreateUser(ctx context.Context, pb *ttnpb.User) (*ttnpb.User userModel.ProfilePictureID = &userModel.ProfilePicture.ID } + if pb.ConsolePreferences != nil { + b, err := jsonpb.TTN().Marshal(pb.ConsolePreferences) + if err != nil { + return nil, err + } + userModel.ConsolePreferences = b + } + // Run user+account creation in a transaction if we're not already in one. err := s.transact(ctx, func(ctx context.Context, tx bun.IDB) error { _, err := tx.NewInsert(). @@ -257,6 +277,11 @@ func (*userStore) selectWithFields(q *bun.SelectQuery, fieldMask store.FieldMask "temporary_password", "temporary_password_created_at", "temporary_password_expires_at": // Proto name equals model name. columns = append(columns, f) + case "console_preferences", + "console_preferences.console_theme", + "console_preferences.dashboard_layouts", + "console_preferences.sort_by": + columns = append(columns, "console_preferences") case "attributes": q = q.Relation("Attributes") case "administrative_contact": @@ -457,6 +482,15 @@ func (s *userStore) updateUserModel( //nolint:gocyclo ) (err error) { columns := store.FieldMask{"updated_at"} + consolePreferences := &ttnpb.UserConsolePreferences{} + updateConsolePreferences := false + + if ttnpb.HasAnyField(ttnpb.TopLevelFields(fieldMask), "console_preferences") && len(model.ConsolePreferences) > 0 { + if err := jsonpb.TTN().Unmarshal(model.ConsolePreferences, consolePreferences); err != nil { + return err + } + } + for _, field := range fieldMask { switch field { case "name": @@ -549,7 +583,30 @@ func (s *userStore) updateUserModel( //nolint:gocyclo model.ProfilePictureID = nil columns = append(columns, "profile_picture_id") } + + case "console_preferences": + updateConsolePreferences = true + consolePreferences = pb.ConsolePreferences + case "console_preferences.console_theme": + updateConsolePreferences = true + consolePreferences.ConsoleTheme = pb.ConsolePreferences.ConsoleTheme + case "console_preferences.dashboard_layouts": + updateConsolePreferences = true + consolePreferences.DashboardLayouts = pb.ConsolePreferences.GetDashboardLayouts() + case "console_preferences.sort_by": + updateConsolePreferences = true + consolePreferences.SortBy = pb.ConsolePreferences.GetSortBy() + } + } + + // By separating the update of the console preferences we can allow for partial updates. + if updateConsolePreferences { + b, err := jsonpb.TTN().Marshal(consolePreferences) + if err != nil { + return err } + model.ConsolePreferences = b + columns = append(columns, "console_preferences") } _, err = s.DB.NewUpdate(). From 6b3455f1db47233a5c0096a195aadc99272ada29 Mon Sep 17 00:00:00 2001 From: Nicholas Cristofaro Date: Tue, 23 Jan 2024 14:24:08 -0300 Subject: [PATCH 4/5] is: Add console_preferences to user_store tests --- pkg/identityserver/storetest/user_store.go | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/pkg/identityserver/storetest/user_store.go b/pkg/identityserver/storetest/user_store.go index 6e0136feb3..52410a9629 100644 --- a/pkg/identityserver/storetest/user_store.go +++ b/pkg/identityserver/storetest/user_store.go @@ -72,6 +72,9 @@ func (st *StoreTest) TestUserStoreCRUD(t *T) { TemporaryPasswordCreatedAt: timestamppb.New(stamp), TemporaryPasswordExpiresAt: timestamppb.New(stamp.Add(time.Hour)), ProfilePicture: picture, + ConsolePreferences: &ttnpb.UserConsolePreferences{ + ConsoleTheme: ttnpb.ConsoleTheme_CONSOLE_THEME_LIGHT, + }, }) if a.So(err, should.BeNil) && a.So(created, should.NotBeNil) { @@ -91,6 +94,11 @@ func (st *StoreTest) TestUserStoreCRUD(t *T) { a.So(*ttnpb.StdTime(created.TemporaryPasswordCreatedAt), should.Equal, stamp) a.So(*ttnpb.StdTime(created.TemporaryPasswordExpiresAt), should.Equal, stamp.Add(time.Hour)) a.So(created.ProfilePicture, should.Resemble, picture) + a.So( + created.ConsolePreferences, + should.Resemble, + &ttnpb.UserConsolePreferences{ConsoleTheme: ttnpb.ConsoleTheme_CONSOLE_THEME_LIGHT}, + ) a.So(*ttnpb.StdTime(created.CreatedAt), should.HappenWithin, 5*time.Second, start) a.So(*ttnpb.StdTime(created.UpdatedAt), should.HappenWithin, 5*time.Second, start) } @@ -208,6 +216,12 @@ func (st *StoreTest) TestUserStoreCRUD(t *T) { TemporaryPasswordCreatedAt: timestamppb.New(stamp), TemporaryPasswordExpiresAt: timestamppb.New(stamp.Add(time.Hour)), ProfilePicture: updatedPicture, + ConsolePreferences: &ttnpb.UserConsolePreferences{ + ConsoleTheme: ttnpb.ConsoleTheme_CONSOLE_THEME_DARK, + DashboardLayouts: &ttnpb.UserConsolePreferences_DashboardLayouts{ + ApiKey: ttnpb.DashboardLayout_DASHBOARD_LAYOUT_LIST, + }, + }, }, mask) if a.So(err, should.BeNil) && a.So(updated, should.NotBeNil) { a.So(updated.GetIds().GetUserId(), should.Equal, "foo") @@ -226,6 +240,16 @@ func (st *StoreTest) TestUserStoreCRUD(t *T) { a.So(*ttnpb.StdTime(updated.TemporaryPasswordCreatedAt), should.Equal, stamp) a.So(*ttnpb.StdTime(updated.TemporaryPasswordExpiresAt), should.Equal, stamp.Add(time.Hour)) a.So(updated.ProfilePicture, should.Resemble, updatedPicture) + a.So( + updated.ConsolePreferences, + should.Resemble, + &ttnpb.UserConsolePreferences{ + ConsoleTheme: ttnpb.ConsoleTheme_CONSOLE_THEME_DARK, + DashboardLayouts: &ttnpb.UserConsolePreferences_DashboardLayouts{ + ApiKey: ttnpb.DashboardLayout_DASHBOARD_LAYOUT_LIST, + }, + }, + ) 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 c5dfbef73a1ca9d6813f307642220afb43e8bc1d Mon Sep 17 00:00:00 2001 From: Nicholas Cristofaro Date: Sun, 28 Jan 2024 19:05:33 -0300 Subject: [PATCH 5/5] is: Add ConsolePreferences test case for user registry --- pkg/identityserver/user_registry_test.go | 58 ++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/pkg/identityserver/user_registry_test.go b/pkg/identityserver/user_registry_test.go index 9ae4b5b8d9..54daf10905 100644 --- a/pkg/identityserver/user_registry_test.go +++ b/pkg/identityserver/user_registry_test.go @@ -401,6 +401,64 @@ func TestUsersCRUD(t *testing.T) { } }) }) + + t.Run("ConsolePreferences", func(t *testing.T) { // nolint:paralleltest + a, ctx := test.New(t) + got, err := reg.Update(ctx, &ttnpb.UpdateUserRequest{ + User: &ttnpb.User{ + Ids: usr1.GetIds(), + ConsolePreferences: &ttnpb.UserConsolePreferences{ + ConsoleTheme: ttnpb.ConsoleTheme_CONSOLE_THEME_DARK, + SortBy: &ttnpb.UserConsolePreferences_SortBy{ + ApiKey: "name", + Application: "name", + Gateway: "name", + Organization: "name", + User: "name", + }, + DashboardLayouts: &ttnpb.UserConsolePreferences_DashboardLayouts{ + ApiKey: ttnpb.DashboardLayout_DASHBOARD_LAYOUT_GRID, + Application: ttnpb.DashboardLayout_DASHBOARD_LAYOUT_GRID, + Gateway: ttnpb.DashboardLayout_DASHBOARD_LAYOUT_GRID, + Organization: ttnpb.DashboardLayout_DASHBOARD_LAYOUT_GRID, + User: ttnpb.DashboardLayout_DASHBOARD_LAYOUT_GRID, + Overview: ttnpb.DashboardLayout_DASHBOARD_LAYOUT_GRID, + }, + }, + }, + FieldMask: ttnpb.FieldMask( + "console_preferences.console_theme", + "console_preferences.dashboard_layouts", + "console_preferences.sort_by", + ), + }, creds) + if a.So(err, should.BeNil) { + a.So(got.ConsolePreferences.ConsoleTheme, should.Equal, ttnpb.ConsoleTheme_CONSOLE_THEME_DARK) + a.So( + got.ConsolePreferences.GetSortBy(), + should.Resemble, + &ttnpb.UserConsolePreferences_SortBy{ + ApiKey: "name", + Application: "name", + Gateway: "name", + Organization: "name", + User: "name", + }, + ) + a.So( + got.ConsolePreferences.GetDashboardLayouts(), + should.Resemble, + &ttnpb.UserConsolePreferences_DashboardLayouts{ + ApiKey: ttnpb.DashboardLayout_DASHBOARD_LAYOUT_GRID, + Application: ttnpb.DashboardLayout_DASHBOARD_LAYOUT_GRID, + Gateway: ttnpb.DashboardLayout_DASHBOARD_LAYOUT_GRID, + Organization: ttnpb.DashboardLayout_DASHBOARD_LAYOUT_GRID, + User: ttnpb.DashboardLayout_DASHBOARD_LAYOUT_GRID, + Overview: ttnpb.DashboardLayout_DASHBOARD_LAYOUT_GRID, + }, + ) + } + }) }) t.Run("Update Password", func(t *testing.T) { // nolint:paralleltest