Skip to content

Commit

Permalink
Merge pull request #7272 from TheThingsNetwork/feature/claim-gateways…
Browse files Browse the repository at this point in the history
…-using-qr-be

Endpoint for claiming gateways using a qr code
  • Loading branch information
vlasebian authored Sep 10, 2024
2 parents 1a759c3 + 57ddabc commit 8298a38
Show file tree
Hide file tree
Showing 23 changed files with 2,074 additions and 154 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ For details about compatibility between different releases, see the **Commitment
- Option to filter out non-gateway related frequency plans.
- `ListFrequencyPlans` RPC has a new `gateways-only` flag.
- Option to pause application webhooks.
- Endpoint for claiming gateways using a qr code

### Changed

Expand Down
46 changes: 46 additions & 0 deletions api/ttn/lorawan/v3/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -743,10 +743,13 @@
- [Message `GetQRCodeFormatRequest`](#ttn.lorawan.v3.GetQRCodeFormatRequest)
- [Message `ParseEndDeviceQRCodeRequest`](#ttn.lorawan.v3.ParseEndDeviceQRCodeRequest)
- [Message `ParseEndDeviceQRCodeResponse`](#ttn.lorawan.v3.ParseEndDeviceQRCodeResponse)
- [Message `ParseGatewayQRCodeRequest`](#ttn.lorawan.v3.ParseGatewayQRCodeRequest)
- [Message `ParseGatewayQRCodeResponse`](#ttn.lorawan.v3.ParseGatewayQRCodeResponse)
- [Message `QRCodeFormat`](#ttn.lorawan.v3.QRCodeFormat)
- [Message `QRCodeFormats`](#ttn.lorawan.v3.QRCodeFormats)
- [Message `QRCodeFormats.FormatsEntry`](#ttn.lorawan.v3.QRCodeFormats.FormatsEntry)
- [Service `EndDeviceQRCodeGenerator`](#ttn.lorawan.v3.EndDeviceQRCodeGenerator)
- [Service `GatewayQRCodeGenerator`](#ttn.lorawan.v3.GatewayQRCodeGenerator)
- [File `ttn/lorawan/v3/regional.proto`](#ttn/lorawan/v3/regional.proto)
- [Message `ConcentratorConfig`](#ttn.lorawan.v3.ConcentratorConfig)
- [Message `ConcentratorConfig.Channel`](#ttn.lorawan.v3.ConcentratorConfig.Channel)
Expand Down Expand Up @@ -10542,6 +10545,34 @@ The Pba service allows clients to manage peering through Packet Broker.
| `format_id` | [`string`](#string) | | Identifier of the format used to successfully parse the QR code data. |
| `end_device_template` | [`EndDeviceTemplate`](#ttn.lorawan.v3.EndDeviceTemplate) | | |

### <a name="ttn.lorawan.v3.ParseGatewayQRCodeRequest">Message `ParseGatewayQRCodeRequest`</a>

| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `format_id` | [`string`](#string) | | QR code format identifier. If this field is not specified, the server will default to ttigpro1. |
| `qr_code` | [`bytes`](#bytes) | | Raw QR code contents. |

#### Field Rules

| Field | Validations |
| ----- | ----------- |
| `format_id` | <p>`string.max_len`: `36`</p><p>`string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$|^$`</p> |
| `qr_code` | <p>`bytes.min_len`: `10`</p><p>`bytes.max_len`: `1024`</p> |

### <a name="ttn.lorawan.v3.ParseGatewayQRCodeResponse">Message `ParseGatewayQRCodeResponse`</a>

| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `format_id` | [`string`](#string) | | Identifier of the format used to parse the QR code data. |
| `gateway_eui` | [`bytes`](#bytes) | | |
| `owner_token` | [`string`](#string) | | |

#### Field Rules

| Field | Validations |
| ----- | ----------- |
| `gateway_eui` | <p>`bytes.len`: `8`</p> |

### <a name="ttn.lorawan.v3.QRCodeFormat">Message `QRCodeFormat`</a>

| Field | Type | Label | Description |
Expand Down Expand Up @@ -10597,6 +10628,21 @@ The EndDeviceQRCodeGenerator service provides functionality to generate and pars
| `Parse` | `POST` | `/api/v3/qr-codes/end-devices/parse` | `*` |
| `Parse` | `POST` | `/api/v3/qr-codes/end-devices/{format_id}/parse` | `*` |

### <a name="ttn.lorawan.v3.GatewayQRCodeGenerator">Service `GatewayQRCodeGenerator`</a>

The GatewayQRCodeGenerator service provides functionality to generate and parse QR codes for gateways.

| Method Name | Request Type | Response Type | Description |
| ----------- | ------------ | ------------- | ------------|
| `Parse` | [`ParseGatewayQRCodeRequest`](#ttn.lorawan.v3.ParseGatewayQRCodeRequest) | [`ParseGatewayQRCodeResponse`](#ttn.lorawan.v3.ParseGatewayQRCodeResponse) | Parse QR Codes of known formats and return the information contained within. |

#### HTTP bindings

| Method Name | Method | Pattern | Body |
| ----------- | ------ | ------- | ---- |
| `Parse` | `POST` | `/api/v3/qr-codes/gateways/parse` | `*` |
| `Parse` | `POST` | `/api/v3/qr-codes/gateways/{format_id}/parse` | `*` |

## <a name="ttn/lorawan/v3/regional.proto">File `ttn/lorawan/v3/regional.proto`</a>

### <a name="ttn.lorawan.v3.ConcentratorConfig">Message `ConcentratorConfig`</a>
Expand Down
139 changes: 128 additions & 11 deletions api/ttn/lorawan/v3/api.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,9 @@
"name": "EndDeviceQRCodeGenerator",
"description": "Generate and parse end device QR codes."
},
{
"name": "GatewayQRCodeGenerator"
},
{
"name": "EntityRegistrySearch",
"description": "Search for entities in the Entity Registry."
Expand Down Expand Up @@ -13142,7 +13145,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/EndDeviceQRCodeGeneratorParseBody"
"$ref": "#/definitions/v3EndDeviceQRCodeGeneratorParseBody"
}
}
],
Expand All @@ -13151,6 +13154,79 @@
]
}
},
"/qr-codes/gateways/parse": {
"post": {
"summary": "Parse QR Codes of known formats and return the information contained within.",
"operationId": "GatewayQRCodeGenerator_Parse",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/v3ParseGatewayQRCodeResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/googlerpcStatus"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v3ParseGatewayQRCodeRequest"
}
}
],
"tags": [
"GatewayQRCodeGenerator"
]
}
},
"/qr-codes/gateways/{format_id}/parse": {
"post": {
"summary": "Parse QR Codes of known formats and return the information contained within.",
"operationId": "GatewayQRCodeGenerator_Parse2",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/v3ParseGatewayQRCodeResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/googlerpcStatus"
}
}
},
"parameters": [
{
"name": "format_id",
"description": "QR code format identifier.\nIf this field is not specified, the server will default to ttigpro1.",
"in": "path",
"required": true,
"type": "string"
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v3GatewayQRCodeGeneratorParseBody"
}
}
],
"tags": [
"GatewayQRCodeGenerator"
]
}
},
"/search/accounts": {
"get": {
"summary": "Search for accounts that match the conditions specified in the request.",
Expand Down Expand Up @@ -17413,16 +17489,6 @@
}
}
},
"EndDeviceQRCodeGeneratorParseBody": {
"type": "object",
"properties": {
"qr_code": {
"type": "string",
"format": "byte",
"description": "Raw QR code contents."
}
}
},
"EventAuthentication": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -23054,6 +23120,16 @@
}
}
},
"v3EndDeviceQRCodeGeneratorParseBody": {
"type": "object",
"properties": {
"qr_code": {
"type": "string",
"format": "byte",
"description": "Raw QR code contents."
}
}
},
"v3EndDeviceRegistryCreateBody": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -24281,6 +24357,16 @@
},
"description": "GatewayDown contains downlink messages for the gateway."
},
"v3GatewayQRCodeGeneratorParseBody": {
"type": "object",
"properties": {
"qr_code": {
"type": "string",
"format": "byte",
"description": "Raw QR code contents."
}
}
},
"v3GatewayRadio": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -27953,6 +28039,37 @@
}
}
},
"v3ParseGatewayQRCodeRequest": {
"type": "object",
"properties": {
"format_id": {
"type": "string",
"description": "QR code format identifier.\nIf this field is not specified, the server will default to ttigpro1."
},
"qr_code": {
"type": "string",
"format": "byte",
"description": "Raw QR code contents."
}
}
},
"v3ParseGatewayQRCodeResponse": {
"type": "object",
"properties": {
"format_id": {
"type": "string",
"description": "Identifier of the format used to parse the QR code data."
},
"gateway_eui": {
"type": "string",
"format": "string",
"example": "70B3D57ED000ABCD"
},
"owner_token": {
"type": "string"
}
}
},
"v3PayloadFormatter": {
"type": "string",
"enum": [
Expand Down
51 changes: 51 additions & 0 deletions api/ttn/lorawan/v3/qrcodegenerator.proto
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import "google/api/annotations.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
import "protoc-gen-openapiv2/options/annotations.proto";
import "thethings/json/annotations.proto";
import "ttn/lorawan/v3/end_device.proto";
import "ttn/lorawan/v3/picture.proto";
import "validate/validate.proto";
Expand Down Expand Up @@ -130,3 +131,53 @@ service EndDeviceQRCodeGenerator {
};
}
}

message ParseGatewayQRCodeRequest {
// QR code format identifier.
// If this field is not specified, the server will default to ttigpro1.
string format_id = 1 [(validate.rules).string = {
pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$|^$",
max_len: 36
}];
// Raw QR code contents.
bytes qr_code = 2 [(validate.rules).bytes = {
min_len: 10,
max_len: 1024
}];
}

message ParseGatewayQRCodeResponse {
// Identifier of the format used to parse the QR code data.
string format_id = 1;
bytes gateway_eui = 2 [
(validate.rules).bytes = {
len: 8,
ignore_empty: true
},
(thethings.json.field) = {
marshaler_func: "go.thethings.network/lorawan-stack/v3/pkg/types.MarshalHEXBytes",
unmarshaler_func: "go.thethings.network/lorawan-stack/v3/pkg/types.Unmarshal8Bytes"
},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
type: STRING,
format: "string",
example: "\"70B3D57ED000ABCD\""
}
];
string owner_token = 3;
}

// The GatewayQRCodeGenerator service provides functionality to generate and parse QR codes for gateways.
service GatewayQRCodeGenerator {
// Parse QR Codes of known formats and return the information contained within.
rpc Parse(ParseGatewayQRCodeRequest) returns (ParseGatewayQRCodeResponse) {
option (google.api.http) = {
post: "/qr-codes/gateways/parse",
body: "*"
additional_bindings {
post: "/qr-codes/gateways/{format_id}/parse"
body: "*"
}
};
}
}
27 changes: 27 additions & 0 deletions config/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -9026,6 +9026,33 @@
"file": "enddevices.go"
}
},
"error:pkg/qrcodegenerator/qrcode/gateways:invalid_format": {
"translations": {
"en": "invalid format"
},
"description": {
"package": "pkg/qrcodegenerator/qrcode/gateways",
"file": "gateways.go"
}
},
"error:pkg/qrcodegenerator/qrcode/gateways:invalid_length": {
"translations": {
"en": "invalid length"
},
"description": {
"package": "pkg/qrcodegenerator/qrcode/gateways",
"file": "gateways.go"
}
},
"error:pkg/qrcodegenerator/qrcode/gateways:unknown_format": {
"translations": {
"en": "format unknown"
},
"description": {
"package": "pkg/qrcodegenerator/qrcode/gateways",
"file": "gateways.go"
}
},
"error:pkg/qrcodegenerator:format_not_found": {
"translations": {
"en": "format `{id}` not found"
Expand Down
2 changes: 1 addition & 1 deletion pkg/deviceclaimingserver/grpc_gateways_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ var (
authorizedCallOpt = grpc.PerRPCCredentials(authorizedMD)
)

func TestGatewayClaimingServer(t *testing.T) { // nolint:paralleltest
func TestGatewayClaimingServer(t *testing.T) { //nolint:paralleltest
a := assertions.New(t)
ctx := log.NewContext(test.Context(), test.GetLogger(t))
ctx, cancelCtx := context.WithCancel(ctx)
Expand Down
Loading

0 comments on commit 8298a38

Please sign in to comment.