diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc new file mode 100644 index 00000000..559c027b --- /dev/null +++ b/CHANGELOG.adoc @@ -0,0 +1,174 @@ +:showtitle: +:toc: left +:icons: font +:toclevels: 1 + += CHANGELOG + +== RFD API Changes: v0.13.0 to v0.14.0 + +=== BREAKING CHANGES + +==== 1. User Endpoint Response Type Changes + +*Affected Endpoints:* + +* `POST /api-user` (create_api_user) +* `POST /api-user/{user_id}` (update_api_user) +* `POST /api-user/{user_id}/group` (add_api_user_to_group) +* `DELETE /api-user/{user_id}/group/{group_id}` (remove_api_user_from_group) + +*Change Details:* + +These endpoints previously returned `ApiUser_for_RfdPermission` directly: + +[source,json] +---- +{ + "id": "uuid", + "created_at": "timestamp", + "updated_at": "timestamp", + "deleted_at": null, + "groups": ["group-uuid"], + "permissions": { ... } +} +---- + +Now they return `GetUserResponse_for_RfdPermission`, which wraps the user info: + +[source,json] +---- +{ + "info": { + "id": "uuid", + "created_at": "timestamp", + "updated_at": "timestamp", + "deleted_at": null, + "groups": ["group-uuid"], + "permissions": { ... } + }, + "providers": [ + { + "id": "provider-uuid", + "user_id": "uuid", + "provider": "github", + "provider_id": "github-id", + "emails": ["email@example.com"], + "display_names": ["Display Name"], + "created_at": "timestamp", + "updated_at": "timestamp", + "deleted_at": null + } + ] +} +---- + +*Breaking Reason:* Client code must be updated to access user data through the `info` property instead of at the root level. The addition of the `providers` array is new information that wasn't previously available in these responses. + +*SDK Impact:* + +TypeScript (rfd-ts): + +[source,typescript] +---- +// Before (v0.13.0) +const response: ApiUser_for_RfdPermission = await client.createApiUser({ body }); + +// After (v0.14.0) +const response: GetUserResponse_for_RfdPermission = await client.createApiUser({ body }); +// Access user info: response.info +// Access providers: response.providers +---- + +Rust (rfd-sdk): + +[source,rust] +---- +// Before (v0.13.0) +let response: ApiUserForRfdPermission = client.create_api_user().body(body).send().await?; + +// After (v0.14.0) +let response: GetUserResponseForRfdPermission = client.create_api_user().body(body).send().await?; +// Access user info: response.info +// Access providers: response.providers +---- + +''' + +=== NON-BREAKING CHANGES + +==== 1. New Endpoint: Get Group Members + +*Added:* `GET /group-membership/{group_id}` (operation ID: `get_group_members`) + +*Description:* Retrieve all members of a specific access group. + +*Parameters:* + +* `group_id` (path): TypedUuidForAccessGroupId - The group ID to query + +*Response:* Array of `GetUserResponse_for_RfdPermission` objects + +*SDK Usage:* + +TypeScript: + +[source,typescript] +---- +const members = await client.getGroupMembers({ + path: { groupId: 'group-uuid' } +}); +---- + +Rust: + +[source,rust] +---- +let members = client.get_group_members() + .group_id(group_id) + .send() + .await?; +---- + +''' + +=== Migration Guide + +==== For Breaking Changes + +If you're using any of these endpoints: + +* `POST /api-user` (createApiUser) +* `POST /api-user/{user_id}` (updateApiUser) +* `POST /api-user/{user_id}/group` (addApiUserToGroup) +* `DELETE /api-user/{user_id}/group/{group_id}` (removeApiUserFromGroup) + +You must update your code to handle the new response structure: + +*TypeScript:* + +[source,typescript] +---- +// Before +const user = await api.createApiUser({ body: params }); +console.log(user.id); // ❌ Will fail in v0.14.0 + +// After +const response = await api.createApiUser({ body: params }); +console.log(response.info.id); // ✅ Correct for v0.14.0 +console.log(response.providers); // New data available +---- + +*Rust:* + +[source,rust] +---- +// Before +let user = client.create_api_user().body(params).send().await?; +println!("{}", user.id); // ❌ Will fail in v0.14.0 + +// After +let response = client.create_api_user().body(params).send().await?; +println!("{}", response.info.id); // ✅ Correct for v0.14.0 +// Access response.providers for additional data +---- diff --git a/Cargo.lock b/Cargo.lock index 543a42d0..b1d1e7c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -767,7 +767,7 @@ dependencies = [ [[package]] name = "dropshot-authorization-header" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/v-api#dcac9d795bbd3c93a09de4b5f7c8c0bff3a22a77" +source = "git+https://github.com/oxidecomputer/v-api#1ba9ce83fa58a543c23e7da80590008c3e3c33bb" dependencies = [ "async-trait", "base64", @@ -3094,7 +3094,7 @@ dependencies = [ [[package]] name = "rfd-api" -version = "0.13.1" +version = "0.14.0" dependencies = [ "anyhow", "async-bb8-diesel", @@ -3160,7 +3160,7 @@ dependencies = [ [[package]] name = "rfd-cli" -version = "0.13.1" +version = "0.14.0" dependencies = [ "anyhow", "chrono", @@ -3247,7 +3247,7 @@ dependencies = [ [[package]] name = "rfd-processor" -version = "0.13.1" +version = "0.14.0" dependencies = [ "async-trait", "base64", @@ -3289,7 +3289,7 @@ dependencies = [ [[package]] name = "rfd-sdk" -version = "0.13.1" +version = "0.14.0" dependencies = [ "chrono", "progenitor-client", @@ -4712,7 +4712,7 @@ dependencies = [ [[package]] name = "v-api" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/v-api#dcac9d795bbd3c93a09de4b5f7c8c0bff3a22a77" +source = "git+https://github.com/oxidecomputer/v-api#1ba9ce83fa58a543c23e7da80590008c3e3c33bb" dependencies = [ "async-trait", "base64", @@ -4757,7 +4757,7 @@ dependencies = [ [[package]] name = "v-api-installer" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/v-api#dcac9d795bbd3c93a09de4b5f7c8c0bff3a22a77" +source = "git+https://github.com/oxidecomputer/v-api#1ba9ce83fa58a543c23e7da80590008c3e3c33bb" dependencies = [ "diesel", "diesel_migrations", @@ -4766,7 +4766,7 @@ dependencies = [ [[package]] name = "v-api-permission-derive" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/v-api#dcac9d795bbd3c93a09de4b5f7c8c0bff3a22a77" +source = "git+https://github.com/oxidecomputer/v-api#1ba9ce83fa58a543c23e7da80590008c3e3c33bb" dependencies = [ "heck", "proc-macro2", @@ -4777,7 +4777,7 @@ dependencies = [ [[package]] name = "v-model" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/v-api#dcac9d795bbd3c93a09de4b5f7c8c0bff3a22a77" +source = "git+https://github.com/oxidecomputer/v-api#1ba9ce83fa58a543c23e7da80590008c3e3c33bb" dependencies = [ "async-bb8-diesel", "async-trait", diff --git a/rfd-api-spec.json b/rfd-api-spec.json index 9a76d76d..64a9eaaa 100644 --- a/rfd-api-spec.json +++ b/rfd-api-spec.json @@ -7,7 +7,7 @@ "url": "https://oxide.computer", "email": "augustus@oxidecomputer.com" }, - "version": "0.13.1" + "version": "0.14.0" }, "paths": { "/.well-known/jwks.json": { @@ -102,7 +102,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiUser_for_RfdPermission" + "$ref": "#/components/schemas/GetUserResponse_for_RfdPermission" } } } @@ -178,7 +178,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiUser_for_RfdPermission" + "$ref": "#/components/schemas/GetUserResponse_for_RfdPermission" } } } @@ -266,7 +266,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiUser_for_RfdPermission" + "$ref": "#/components/schemas/GetUserResponse_for_RfdPermission" } } } @@ -308,7 +308,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiUser_for_RfdPermission" + "$ref": "#/components/schemas/GetUserResponse_for_RfdPermission" } } } @@ -761,10 +761,10 @@ "content": { "application/json": { "schema": { - "title": "Array_of_ApiUser_for_RfdPermission", + "title": "Array_of_GetUserResponse_for_RfdPermission", "type": "array", "items": { - "$ref": "#/components/schemas/ApiUser_for_RfdPermission" + "$ref": "#/components/schemas/GetUserResponse_for_RfdPermission" } } } diff --git a/rfd-api/Cargo.toml b/rfd-api/Cargo.toml index ed2a2916..670baccb 100644 --- a/rfd-api/Cargo.toml +++ b/rfd-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rfd-api" -version = "0.13.1" +version = "0.14.0" edition = "2021" repository = "https://github.com/oxidecomputer/rfd-api" diff --git a/rfd-cli/Cargo.toml b/rfd-cli/Cargo.toml index 0ad37892..7baff291 100644 --- a/rfd-cli/Cargo.toml +++ b/rfd-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rfd-cli" -version = "0.13.1" +version = "0.14.0" edition = "2021" [features] diff --git a/rfd-cli/src/main.rs b/rfd-cli/src/main.rs index cea7f4b9..6ebac121 100644 --- a/rfd-cli/src/main.rs +++ b/rfd-cli/src/main.rs @@ -378,9 +378,7 @@ impl ProgenitorCliConfig for Context { T: schemars::JsonSchema + serde::Serialize + std::fmt::Debug, { match T::schema_name().as_str() { - "ApiUserForApiPermissionResponse" => { - self.printer().unwrap().output_api_user(reserialize(value)) - } + // User response types "Array_of_GetUserResponseForRfdPermission" => self .printer() .unwrap() @@ -388,33 +386,45 @@ impl ProgenitorCliConfig for Context { "GetUserResponseForRfdPermission" => { self.printer().unwrap().output_user(reserialize(value)) } + "ApiUserContactEmail" => self + .printer() + .unwrap() + .output_api_user_contact_email(reserialize(value)), + "ApiUserLinkRequestResponse" => self + .printer() + .unwrap() + .output_api_user_link_request_response(reserialize(value)), + + // API key response types "Array_of_ApiKeyResponseForRfdPermission" => self .printer() .unwrap() .output_api_key_list(reserialize(value)), - "InitialApiKeyResponse" => self + "InitialApiKeyResponseForRfdPermission" => self .printer() .unwrap() .output_api_key_initial(reserialize(value)), "ApiKeyResponseForRfdPermission" => { self.printer().unwrap().output_api_key(reserialize(value)) } - "Array_of_AccessGroupForApiPermissionResponse" => self - .printer() - .unwrap() - .output_group_list(reserialize(value)), - "AccessGroupForApiPermissionResponse" => { - self.printer().unwrap().output_api_user(reserialize(value)) - } + + // Group response types "Array_of_AccessGroupForRfdPermission" => self .printer() .unwrap() .output_group_list(reserialize(value)), + "AccessGroupForRfdPermission" => { + self.printer().unwrap().output_group(reserialize(value)) + } + + // Mapper response types "Array_of_Mapper" => self .printer() .unwrap() .output_mapper_list(reserialize(value)), "Mapper" => self.printer().unwrap().output_mapper(reserialize(value)), + + // OAuth client response types "Array_of_OAuthClient" => self .printer() .unwrap() @@ -435,30 +445,16 @@ impl ProgenitorCliConfig for Context { .printer() .unwrap() .output_oauth_secret(reserialize(value)), - "RfdWithoutContent" => self.printer().unwrap().output_rfd_meta(reserialize(value)), - "Array_of_RfdWithoutContent" => { - self.printer().unwrap().output_rfd_list(reserialize(value)) - } - "RfdWithRaw" => self.printer().unwrap().output_rfd_full(reserialize(value)), - "SearchResults" => self + "OAuthAuthzCodeExchangeResponse" => self .printer() .unwrap() - .output_search_results(reserialize(value)), - "RfdAttr" => self.printer().unwrap().output_rfd_attr(reserialize(value)), - "RfdRevisionMeta" => self + .output_oauth_authz_code_exchange_response(reserialize(value)), + "OAuthProviderInfo" => self .printer() .unwrap() - .output_rfd_revision_meta(reserialize(value)), - "Array_of_RfdRevisionMeta" => self - .printer() - .unwrap() - .output_rfd_revision_meta_list(reserialize(value)), - "ReserveRfdResponse" => self - .printer() - .unwrap() - .output_reserved_rfd(reserialize(value)), - "Array_of_Job" => self.printer().unwrap().output_job_list(reserialize(value)), + .output_oauth_provider_info(reserialize(value)), + // Magic link response types "Array_of_MagicLink" => self .printer() .unwrap() @@ -479,6 +475,54 @@ impl ProgenitorCliConfig for Context { .printer() .unwrap() .output_magic_link_secret(reserialize(value)), + "MagicLinkExchangeResponse" => self + .printer() + .unwrap() + .output_magic_link_exchange_response(reserialize(value)), + "MagicLinkSendResponse" => self + .printer() + .unwrap() + .output_magic_link_send_response(reserialize(value)), + + // RFD response types + "RfdWithoutContent" => self.printer().unwrap().output_rfd_meta(reserialize(value)), + "Array_of_RfdWithoutContent" => { + self.printer().unwrap().output_rfd_list(reserialize(value)) + } + "RfdWithRaw" => self.printer().unwrap().output_rfd_full(reserialize(value)), + "RfdWithPdf" => self + .printer() + .unwrap() + .output_rfd_with_pdf(reserialize(value)), + "Rfd" => self.printer().unwrap().output_rfd(reserialize(value)), + "RfdAttr" => self.printer().unwrap().output_rfd_attr(reserialize(value)), + "RfdRevisionMeta" => self + .printer() + .unwrap() + .output_rfd_revision_meta(reserialize(value)), + "Array_of_RfdRevisionMeta" => self + .printer() + .unwrap() + .output_rfd_revision_meta_list(reserialize(value)), + "ReserveRfdResponse" => self + .printer() + .unwrap() + .output_reserved_rfd(reserialize(value)), + "SearchResults" => self + .printer() + .unwrap() + .output_search_results(reserialize(value)), + + // Job response types + "Array_of_Job" => self.printer().unwrap().output_job_list(reserialize(value)), + + // OpenID/JWKS response types + "Jwks" => self.printer().unwrap().output_jwks(reserialize(value)), + "OpenIdConfiguration" => self + .printer() + .unwrap() + .output_openid_configuration(reserialize(value)), + other => eprintln!( "Unhandled response type: {}. Please report this as a bug.", other diff --git a/rfd-cli/src/printer/json.rs b/rfd-cli/src/printer/json.rs index 292bb674..82a47e7c 100644 --- a/rfd-cli/src/printer/json.rs +++ b/rfd-cli/src/printer/json.rs @@ -23,6 +23,14 @@ impl CliOutput for RfdJsonPrinter { println!("{}", serde_json::to_string(&value).unwrap()) } + fn output_api_user_contact_email(&self, value: types::ApiUserContactEmail) { + println!("{}", serde_json::to_string(&value).unwrap()) + } + + fn output_api_user_link_request_response(&self, value: types::ApiUserLinkRequestResponse) { + println!("{}", serde_json::to_string(&value).unwrap()) + } + fn output_api_key_list(&self, value: Vec) { println!("{}", serde_json::to_string(&value).unwrap()) } @@ -71,6 +79,17 @@ impl CliOutput for RfdJsonPrinter { println!("{}", serde_json::to_string(&value).unwrap()) } + fn output_oauth_authz_code_exchange_response( + &self, + value: types::OAuthAuthzCodeExchangeResponse, + ) { + println!("{}", serde_json::to_string(&value).unwrap()) + } + + fn output_oauth_provider_info(&self, value: types::OAuthProviderInfo) { + println!("{}", serde_json::to_string(&value).unwrap()) + } + fn output_rfd_meta(&self, value: types::RfdWithoutContent) { println!("{}", serde_json::to_string(&value).unwrap()) } @@ -83,6 +102,10 @@ impl CliOutput for RfdJsonPrinter { println!("{}", serde_json::to_string(&value).unwrap()) } + fn output_rfd_with_pdf(&self, value: types::RfdWithPdf) { + println!("{}", serde_json::to_string(&value).unwrap()) + } + fn output_rfd(&self, value: types::Rfd) { println!("{}", serde_json::to_string(&value).unwrap()) } @@ -131,6 +154,22 @@ impl CliOutput for RfdJsonPrinter { println!("{}", serde_json::to_string(&value).unwrap()) } + fn output_magic_link_exchange_response(&self, value: types::MagicLinkExchangeResponse) { + println!("{}", serde_json::to_string(&value).unwrap()) + } + + fn output_magic_link_send_response(&self, value: types::MagicLinkSendResponse) { + println!("{}", serde_json::to_string(&value).unwrap()) + } + + fn output_jwks(&self, value: types::Jwks) { + println!("{}", serde_json::to_string(&value).unwrap()) + } + + fn output_openid_configuration(&self, value: types::OpenIdConfiguration) { + println!("{}", serde_json::to_string(&value).unwrap()) + } + fn output_error(&self, value: &progenitor_client::Error) where T: schemars::JsonSchema + serde::Serialize + std::fmt::Debug, diff --git a/rfd-cli/src/printer/mod.rs b/rfd-cli/src/printer/mod.rs index 85b96db4..1e1460f3 100644 --- a/rfd-cli/src/printer/mod.rs +++ b/rfd-cli/src/printer/mod.rs @@ -19,6 +19,8 @@ pub trait CliOutput { fn output_api_user(&self, value: types::ApiUserForRfdPermission) {} fn output_api_user_list(&self, value: Vec) {} fn output_user(&self, value: types::GetUserResponseForRfdPermission) {} + fn output_api_user_contact_email(&self, value: types::ApiUserContactEmail) {} + fn output_api_user_link_request_response(&self, value: types::ApiUserLinkRequestResponse) {} fn output_api_key_list(&self, value: Vec) {} fn output_api_key_initial(&self, value: types::InitialApiKeyResponseForRfdPermission) {} fn output_api_key(&self, value: types::ApiKeyResponseForRfdPermission) {} @@ -31,9 +33,16 @@ pub trait CliOutput { fn output_oauth_redirect_uri(&self, value: types::OAuthClientRedirectUri) {} fn output_oauth_secret_initial(&self, value: types::InitialOAuthClientSecretResponse) {} fn output_oauth_secret(&self, value: types::OAuthClientSecret) {} + fn output_oauth_authz_code_exchange_response( + &self, + value: types::OAuthAuthzCodeExchangeResponse, + ) { + } + fn output_oauth_provider_info(&self, value: types::OAuthProviderInfo) {} fn output_rfd_meta(&self, value: types::RfdWithoutContent) {} fn output_rfd_list(&self, value: Vec) {} fn output_rfd_full(&self, value: types::RfdWithRaw) {} + fn output_rfd_with_pdf(&self, value: types::RfdWithPdf) {} fn output_rfd(&self, value: types::Rfd) {} fn output_rfd_attr(&self, value: types::RfdAttr) {} fn output_rfd_revision_meta(&self, value: types::RfdRevisionMeta) {} @@ -56,6 +65,10 @@ pub trait CliOutput { fn output_magic_link_secret(&self, value: types::MagicLinkSecret) { println!("{}", serde_json::to_string(&value).unwrap()) } + fn output_magic_link_exchange_response(&self, value: types::MagicLinkExchangeResponse) {} + fn output_magic_link_send_response(&self, value: types::MagicLinkSendResponse) {} + fn output_jwks(&self, value: types::Jwks) {} + fn output_openid_configuration(&self, value: types::OpenIdConfiguration) {} fn output_error(&self, value: &progenitor_client::Error) where T: schemars::JsonSchema + serde::Serialize + std::fmt::Debug; @@ -83,6 +96,20 @@ impl CliOutput for Printer { } } + fn output_api_user_contact_email(&self, value: types::ApiUserContactEmail) { + match self { + Self::Json(printer) => printer.output_api_user_contact_email(value), + Self::Tab(printer) => printer.output_api_user_contact_email(value), + } + } + + fn output_api_user_link_request_response(&self, value: types::ApiUserLinkRequestResponse) { + match self { + Self::Json(printer) => printer.output_api_user_link_request_response(value), + Self::Tab(printer) => printer.output_api_user_link_request_response(value), + } + } + fn output_api_key_list(&self, value: Vec) { match self { Self::Json(printer) => printer.output_api_key_list(value), @@ -167,6 +194,23 @@ impl CliOutput for Printer { } } + fn output_oauth_authz_code_exchange_response( + &self, + value: types::OAuthAuthzCodeExchangeResponse, + ) { + match self { + Self::Json(printer) => printer.output_oauth_authz_code_exchange_response(value), + Self::Tab(printer) => printer.output_oauth_authz_code_exchange_response(value), + } + } + + fn output_oauth_provider_info(&self, value: types::OAuthProviderInfo) { + match self { + Self::Json(printer) => printer.output_oauth_provider_info(value), + Self::Tab(printer) => printer.output_oauth_provider_info(value), + } + } + fn output_rfd_meta(&self, value: types::RfdWithoutContent) { match self { Self::Json(printer) => printer.output_rfd_meta(value), @@ -188,6 +232,13 @@ impl CliOutput for Printer { } } + fn output_rfd_with_pdf(&self, value: types::RfdWithPdf) { + match self { + Self::Json(printer) => printer.output_rfd_with_pdf(value), + Self::Tab(printer) => printer.output_rfd_with_pdf(value), + } + } + fn output_rfd(&self, value: types::Rfd) { match self { Self::Json(printer) => printer.output_rfd(value), @@ -237,6 +288,34 @@ impl CliOutput for Printer { } } + fn output_magic_link_exchange_response(&self, value: types::MagicLinkExchangeResponse) { + match self { + Self::Json(printer) => printer.output_magic_link_exchange_response(value), + Self::Tab(printer) => printer.output_magic_link_exchange_response(value), + } + } + + fn output_magic_link_send_response(&self, value: types::MagicLinkSendResponse) { + match self { + Self::Json(printer) => printer.output_magic_link_send_response(value), + Self::Tab(printer) => printer.output_magic_link_send_response(value), + } + } + + fn output_jwks(&self, value: types::Jwks) { + match self { + Self::Json(printer) => printer.output_jwks(value), + Self::Tab(printer) => printer.output_jwks(value), + } + } + + fn output_openid_configuration(&self, value: types::OpenIdConfiguration) { + match self { + Self::Json(printer) => printer.output_openid_configuration(value), + Self::Tab(printer) => printer.output_openid_configuration(value), + } + } + fn output_error(&self, value: &progenitor_client::Error) where T: schemars::JsonSchema + serde::Serialize + std::fmt::Debug, diff --git a/rfd-cli/src/printer/tab.rs b/rfd-cli/src/printer/tab.rs index cbcbbb9c..7004bcf5 100644 --- a/rfd-cli/src/printer/tab.rs +++ b/rfd-cli/src/printer/tab.rs @@ -6,12 +6,15 @@ use itertools::{EitherOrBoth, Itertools}; use owo_colors::{OwoColorize, Style}; use progenitor_client::ResponseValue; use rfd_sdk::types::{ - self, AccessGroupForRfdPermission, ApiKeyResponseForRfdPermission, ApiUserForRfdPermission, - Error, GetUserResponseForRfdPermission, InitialApiKeyResponseForRfdPermission, - InitialMagicLinkSecretResponse, InitialOAuthClientSecretResponse, Job, MagicLink, - MagicLinkRedirectUri, MagicLinkSecret, Mapper, OAuthClient, OAuthClientRedirectUri, - OAuthClientSecret, PermissionsForRfdPermission, ReserveRfdResponse, RfdAttr, RfdRevisionMeta, - RfdWithRaw, RfdWithoutContent, SearchResultHit, SearchResults, Visibility, + self, AccessGroupForRfdPermission, ApiKeyResponseForRfdPermission, ApiUserContactEmail, + ApiUserForRfdPermission, ApiUserLinkRequestResponse, Error, GetUserResponseForRfdPermission, + InitialApiKeyResponseForRfdPermission, InitialMagicLinkSecretResponse, + InitialOAuthClientSecretResponse, Job, Jwk, Jwks, MagicLink, MagicLinkExchangeResponse, + MagicLinkRedirectUri, MagicLinkSecret, MagicLinkSendResponse, Mapper, + OAuthAuthzCodeExchangeResponse, OAuthClient, OAuthClientRedirectUri, OAuthClientSecret, + OAuthProviderInfo, OpenIdConfiguration, PermissionsForRfdPermission, ReserveRfdResponse, + RfdAttr, RfdPdf, RfdRevisionMeta, RfdWithPdf, RfdWithRaw, RfdWithoutContent, SearchResultHit, + SearchResults, Visibility, }; use std::{collections::HashMap, fmt::Display, fs::File, io::Write, process::Command}; use tabwriter::TabWriter; @@ -53,6 +56,14 @@ impl CliOutput for RfdTabPrinter { self.print_cli_output(&value, None); } + fn output_api_user_contact_email(&self, value: types::ApiUserContactEmail) { + self.print_cli_output(&value, None); + } + + fn output_api_user_link_request_response(&self, value: types::ApiUserLinkRequestResponse) { + self.print_cli_output(&value, None); + } + fn output_api_key_list(&self, value: Vec) { self.print_cli_output(&value, Some("tokens".to_string())); } @@ -101,6 +112,17 @@ impl CliOutput for RfdTabPrinter { self.print_cli_output(&value, None); } + fn output_oauth_authz_code_exchange_response( + &self, + value: types::OAuthAuthzCodeExchangeResponse, + ) { + self.print_cli_output(&value, None); + } + + fn output_oauth_provider_info(&self, value: types::OAuthProviderInfo) { + self.print_cli_output(&value, None); + } + fn output_rfd_meta(&self, value: types::RfdWithoutContent) { self.print_cli_output(&value, None); } @@ -113,6 +135,10 @@ impl CliOutput for RfdTabPrinter { self.print_cli_output(&value, None); } + fn output_rfd_with_pdf(&self, value: types::RfdWithPdf) { + self.print_cli_output(&value, None); + } + fn output_rfd(&self, value: types::Rfd) { self.print_cli_output(&value, None); } @@ -157,6 +183,22 @@ impl CliOutput for RfdTabPrinter { self.print_cli_output(&value, None); } + fn output_magic_link_exchange_response(&self, value: types::MagicLinkExchangeResponse) { + self.print_cli_output(&value, None); + } + + fn output_magic_link_send_response(&self, value: types::MagicLinkSendResponse) { + self.print_cli_output(&value, None); + } + + fn output_jwks(&self, value: types::Jwks) { + self.print_cli_output(&value, None); + } + + fn output_openid_configuration(&self, value: types::OpenIdConfiguration) { + self.print_cli_output(&value, None); + } + fn output_error(&self, value: &progenitor_client::Error) where T: schemars::JsonSchema + serde::Serialize + std::fmt::Debug, @@ -184,6 +226,17 @@ impl TabDisplay for types::Rfd { .unwrap_or_else(|| "--".to_string()), ); printer.print_field(tw, level, "link", &self.link.as_deref().unwrap_or("")); + printer.print_field(tw, level, "created_at", &self.created_at); + printer.print_field(tw, level, "updated_at", &self.updated_at); + printer.print_field( + tw, + level, + "deleted_at", + &self + .deleted_at + .map(|d| d.to_string()) + .unwrap_or_else(|| "--".to_string()), + ); } } @@ -345,6 +398,7 @@ impl TabDisplay for Mapper { &serde_json::to_string(&self.rule).unwrap(), ); printer.print_field(tw, level, "created_at", &self.created_at); + printer.print_field(tw, level, "updated_at", &self.updated_at); printer.print_field( tw, level, @@ -447,6 +501,16 @@ impl TabDisplay for RfdWithoutContent { ); printer.print_field(tw, level, "authors", &self.authors.as_deref().unwrap_or("")); printer.print_field(tw, level, "labels", &self.labels.as_deref().unwrap_or("")); + printer.print_field( + tw, + level, + "format", + &self + .format + .as_ref() + .map(|f| f.to_string()) + .unwrap_or_else(|| "--".to_string()), + ); printer.print_field(tw, level, "link", &self.link.as_deref().unwrap_or("")); printer.print_field( tw, @@ -504,6 +568,16 @@ impl TabDisplay for RfdWithRaw { ); printer.print_field(tw, level, "authors", &self.authors.as_deref().unwrap_or("")); printer.print_field(tw, level, "labels", &self.labels.as_deref().unwrap_or("")); + printer.print_field( + tw, + level, + "format", + &self + .format + .as_ref() + .map(|f| f.to_string()) + .unwrap_or_else(|| "--".to_string()), + ); printer.print_field(tw, level, "link", &self.link.as_deref().unwrap_or("")); printer.print_field( tw, @@ -571,6 +645,24 @@ impl TabDisplay for RfdAttr { impl TabDisplay for SearchResults { fn display(&self, tw: &mut TabWriter>, level: u8, printer: &RfdTabPrinter) { printer.print_field(tw, level, "query", &self.query); + printer.print_field( + tw, + level, + "limit", + &self + .limit + .map(|l| l.to_string()) + .unwrap_or_else(|| "--".to_string()), + ); + printer.print_field( + tw, + level, + "offset", + &self + .offset + .map(|o| o.to_string()) + .unwrap_or_else(|| "--".to_string()), + ); printer.print_field(tw, level, "total hits", &self.hits.len()); writeln!(tw); self.hits.display(tw, level, printer); @@ -736,6 +828,183 @@ impl TabDisplay for InitialMagicLinkSecretResponse { } } +impl TabDisplay for ApiUserContactEmail { + fn display(&self, tw: &mut TabWriter>, level: u8, printer: &RfdTabPrinter) { + printer.print_field(tw, level, "id", &self.id); + printer.print_field(tw, level, "user_id", &self.user_id); + printer.print_field(tw, level, "email", &self.email); + printer.print_field(tw, level, "created_at", &self.created_at); + printer.print_field(tw, level, "updated_at", &self.updated_at); + printer.print_field( + tw, + level, + "deleted_at", + &self + .deleted_at + .map(|d| d.to_string()) + .unwrap_or_else(|| "--".to_string()), + ); + } +} + +impl TabDisplay for ApiUserLinkRequestResponse { + fn display(&self, tw: &mut TabWriter>, level: u8, printer: &RfdTabPrinter) { + printer.print_field(tw, level, "token", &self.token.0); + } +} + +impl TabDisplay for OAuthAuthzCodeExchangeResponse { + fn display(&self, tw: &mut TabWriter>, level: u8, printer: &RfdTabPrinter) { + printer.print_field(tw, level, "access_token", &self.access_token); + printer.print_field(tw, level, "token_type", &self.token_type); + printer.print_field(tw, level, "expires_in", &self.expires_in); + } +} + +impl TabDisplay for OAuthProviderInfo { + fn display(&self, tw: &mut TabWriter>, level: u8, printer: &RfdTabPrinter) { + printer.print_field(tw, level, "provider", &self.provider.to_string()); + printer.print_field(tw, level, "client_id", &self.client_id); + printer.print_field(tw, level, "auth_url_endpoint", &self.auth_url_endpoint); + printer.print_field(tw, level, "token_endpoint", &self.token_endpoint); + printer.print_field( + tw, + level, + "device_code_endpoint", + &self.device_code_endpoint, + ); + printer.print_list(tw, level, "scopes", &self.scopes); + } +} + +impl TabDisplay for RfdWithPdf { + fn display(&self, tw: &mut TabWriter>, level: u8, printer: &RfdTabPrinter) { + printer.print_field(tw, level, "id", &self.id); + printer.print_field(tw, level, "rfd_number", &self.rfd_number); + printer.print_field(tw, level, "title", &self.title.as_deref().unwrap_or("")); + printer.print_field(tw, level, "state", &self.state.as_deref().unwrap_or("")); + printer.print_field( + tw, + level, + "visibility", + match self.visibility { + Visibility::Private => &"private", + Visibility::Public => &"public", + }, + ); + printer.print_field(tw, level, "authors", &self.authors.as_deref().unwrap_or("")); + printer.print_field(tw, level, "labels", &self.labels.as_deref().unwrap_or("")); + printer.print_field( + tw, + level, + "format", + &self + .format + .as_ref() + .map(|f| f.to_string()) + .unwrap_or_else(|| "--".to_string()), + ); + printer.print_field(tw, level, "link", &self.link.as_deref().unwrap_or("")); + printer.print_field( + tw, + level, + "discussion", + &self.discussion.as_deref().unwrap_or(""), + ); + printer.print_field( + tw, + level, + "sha", + &self.sha.as_ref().map(|s| s.as_str()).unwrap_or(""), + ); + printer.print_field( + tw, + level, + "commit", + &self.commit.as_ref().map(|s| s.as_str()).unwrap_or(""), + ); + printer.print_field( + tw, + level, + "committed_at", + &self + .committed_at + .map(|d| d.to_string()) + .unwrap_or_else(|| "--".to_string()), + ); + printer.print_field( + tw, + level, + "latest_major_change_at", + &self + .latest_major_change_at + .map(|d| d.to_string()) + .unwrap_or_else(|| "--".to_string()), + ); + printer.print_field(tw, level, "pdfs", &""); + self.content.display(tw, level + 1, printer); + } +} + +impl TabDisplay for RfdPdf { + fn display(&self, tw: &mut TabWriter>, level: u8, printer: &RfdTabPrinter) { + printer.print_field(tw, level, "id", &self.id); + printer.print_field(tw, level, "source", &self.source.to_string()); + printer.print_field(tw, level, "link", &self.link); + printer.print_field(tw, level, "external_id", &self.external_id); + printer.print_field(tw, level, "rfd_id", &self.rfd_id); + printer.print_field(tw, level, "rfd_revision_id", &self.rfd_revision_id); + printer.print_field(tw, level, "created_at", &self.created_at); + printer.print_field(tw, level, "updated_at", &self.updated_at); + printer.print_field( + tw, + level, + "deleted_at", + &self + .deleted_at + .map(|d| d.to_string()) + .unwrap_or_else(|| "--".to_string()), + ); + } +} + +impl TabDisplay for MagicLinkExchangeResponse { + fn display(&self, tw: &mut TabWriter>, level: u8, printer: &RfdTabPrinter) { + printer.print_field(tw, level, "access_token", &self.access_token); + printer.print_field(tw, level, "token_type", &self.token_type); + printer.print_field(tw, level, "expires_in", &self.expires_in); + } +} + +impl TabDisplay for MagicLinkSendResponse { + fn display(&self, tw: &mut TabWriter>, level: u8, printer: &RfdTabPrinter) { + printer.print_field(tw, level, "attempt_id", &*self.attempt_id); + } +} + +impl TabDisplay for Jwks { + fn display(&self, tw: &mut TabWriter>, level: u8, printer: &RfdTabPrinter) { + printer.print_field(tw, level, "keys", &""); + self.keys.display(tw, level + 1, printer); + } +} + +impl TabDisplay for Jwk { + fn display(&self, tw: &mut TabWriter>, level: u8, printer: &RfdTabPrinter) { + printer.print_field(tw, level, "kid", &self.kid); + printer.print_field(tw, level, "kty", &self.kty); + printer.print_field(tw, level, "use", &self.use_); + printer.print_field(tw, level, "n", &self.n); + printer.print_field(tw, level, "e", &self.e); + } +} + +impl TabDisplay for OpenIdConfiguration { + fn display(&self, tw: &mut TabWriter>, level: u8, printer: &RfdTabPrinter) { + printer.print_field(tw, level, "jwks_uri", &self.jwks_uri); + } +} + impl TabDisplay for Vec where T: TabDisplay, diff --git a/rfd-processor/Cargo.toml b/rfd-processor/Cargo.toml index 9595d57e..6622ff35 100644 --- a/rfd-processor/Cargo.toml +++ b/rfd-processor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rfd-processor" -version = "0.13.1" +version = "0.14.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/rfd-sdk/Cargo.toml b/rfd-sdk/Cargo.toml index 3e22c3ce..19d48681 100644 --- a/rfd-sdk/Cargo.toml +++ b/rfd-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rfd-sdk" -version = "0.13.1" +version = "0.14.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/rfd-sdk/src/generated/sdk.rs b/rfd-sdk/src/generated/sdk.rs index 3a382625..bca53af1 100644 --- a/rfd-sdk/src/generated/sdk.rs +++ b/rfd-sdk/src/generated/sdk.rs @@ -14260,7 +14260,7 @@ pub mod types { /// /// Programmatic access to RFDs /// -/// Version: 0.13.1 +/// Version: 0.14.0 pub struct Client { pub(crate) baseurl: String, pub(crate) client: reqwest::Client, @@ -14301,7 +14301,7 @@ impl Client { impl ClientInfo<()> for Client { fn api_version() -> &'static str { - "0.13.1" + "0.14.0" } fn baseurl(&self) -> &str { @@ -15591,7 +15591,8 @@ pub mod builder { /// Sends a `POST` request to `/api-user` pub async fn send( self, - ) -> Result, Error> { + ) -> Result, Error> + { let Self { client, body } = self; let body = body .and_then(|v| { @@ -15767,7 +15768,8 @@ pub mod builder { /// Sends a `POST` request to `/api-user/{user_id}` pub async fn send( self, - ) -> Result, Error> { + ) -> Result, Error> + { let Self { client, user_id, @@ -15982,7 +15984,8 @@ pub mod builder { /// Sends a `POST` request to `/api-user/{user_id}/group` pub async fn send( self, - ) -> Result, Error> { + ) -> Result, Error> + { let Self { client, user_id, @@ -16075,7 +16078,8 @@ pub mod builder { /// Sends a `DELETE` request to `/api-user/{user_id}/group/{group_id}` pub async fn send( self, - ) -> Result, Error> { + ) -> Result, Error> + { let Self { client, user_id, @@ -17164,7 +17168,7 @@ pub mod builder { pub async fn send( self, ) -> Result< - ResponseValue<::std::vec::Vec>, + ResponseValue<::std::vec::Vec>, Error, > { let Self { client, group_id } = self; diff --git a/rfd-ts/package.json b/rfd-ts/package.json index 60887064..e380cf5a 100644 --- a/rfd-ts/package.json +++ b/rfd-ts/package.json @@ -69,5 +69,5 @@ ] } }, - "version": "0.13.1" + "version": "0.14.0" } diff --git a/rfd-ts/src/Api.ts b/rfd-ts/src/Api.ts index b0c1c94b..3e1b2e3f 100644 --- a/rfd-ts/src/Api.ts +++ b/rfd-ts/src/Api.ts @@ -879,7 +879,7 @@ export class Api { * Pulled from info.version in the OpenAPI schema. Sent in the * `api-version` header on all requests. */ - apiVersion = '0.13.1' + apiVersion = '0.14.0' constructor({ host = '', baseParams = {}, token }: ApiConfig = {}) { this.host = host @@ -941,7 +941,7 @@ export class Api { createApiUser: ({ body, }: { body: ApiUserUpdateParams_for_RfdPermission }, params: FetchParams = {}) => { - return this.request({ + return this.request({ path: `/api-user`, method: 'POST', body, @@ -967,7 +967,7 @@ export class Api { path, body, }: { path: UpdateApiUserPathParams; body: ApiUserUpdateParams_for_RfdPermission }, params: FetchParams = {}) => { - return this.request({ + return this.request({ path: `/api-user/${path.userId}`, method: 'POST', body, @@ -995,7 +995,7 @@ export class Api { path, body, }: { path: AddApiUserToGroupPathParams; body: AddGroupBody }, params: FetchParams = {}) => { - return this.request({ + return this.request({ path: `/api-user/${path.userId}/group`, method: 'POST', body, @@ -1008,7 +1008,7 @@ export class Api { removeApiUserFromGroup: ({ path, }: { path: RemoveApiUserFromGroupPathParams }, params: FetchParams = {}) => { - return this.request({ + return this.request({ path: `/api-user/${path.userId}/group/${path.groupId}`, method: 'DELETE', ...params, @@ -1160,7 +1160,7 @@ export class Api { getGroupMembers: ({ path, }: { path: GetGroupMembersPathParams }, params: FetchParams = {}) => { - return this.request({ + return this.request({ path: `/group-membership/${path.groupId}`, method: 'GET', ...params, diff --git a/rfd-ts/src/util.ts b/rfd-ts/src/util.ts index d3c84eda..f23549b9 100644 --- a/rfd-ts/src/util.ts +++ b/rfd-ts/src/util.ts @@ -51,7 +51,6 @@ export const parseIfDate = (k: string | undefined, v: unknown) => { && (k?.startsWith('time_') || k?.endsWith('_time') || k?.endsWith('_expiration') - || k?.endsWith('_at') || k === 'timestamp') ) { const d = new Date(v)