Skip to content

Commit a77b436

Browse files
Support enabling new Stripe payment provider (#85)
1 parent 11a7600 commit a77b436

File tree

5 files changed

+275
-1
lines changed

5 files changed

+275
-1
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# SaaS RS :: CLI Changelog
22

3+
## [Unreleased]
4+
### Added
5+
- [#84](https://github.com/saas-rs/cli/issues/84) Support enabling new Stripe payment provider
6+
37
## [0.3.6] - 2025-09-27
48
### Changed
59
- [#82](https://github.com/saas-rs/cli/issues/82) Upgrade Rust from 1.88.0 → 1.89.0

src/cmd/enable/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub(super) mod identity_provider;
2+
pub(super) mod payment_provider;
23
pub(super) mod storage_provider;
34

45
use clap::Parser;
@@ -15,6 +16,9 @@ pub enum Subcommand {
1516
#[command(name = "identity-provider", alias = "identityProvider")]
1617
IdentityProvider(identity_provider::Opts),
1718

19+
#[command(name = "payment-provider", alias = "paymentProvider")]
20+
PaymentProvider(payment_provider::Opts),
21+
1822
#[command(name = "storage-provider", alias = "storageProvider")]
1923
StorageProvider(storage_provider::Opts),
2024
}
@@ -24,6 +28,9 @@ pub async fn run(subcommand: Subcommand) -> Result<(), Box<dyn std::error::Error
2428
Subcommand::IdentityProvider(identity_provider::Opts { provider }) => {
2529
identity_provider::run(provider).await?;
2630
}
31+
Subcommand::PaymentProvider(payment_provider::Opts { provider }) => {
32+
payment_provider::run(provider).await?;
33+
}
2734
Subcommand::StorageProvider(storage_provider::Opts { provider }) => {
2835
storage_provider::run(provider).await?;
2936
}

src/cmd/enable/payment_provider.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use crate::cmd::generate::{do_generate, do_generate_preflight};
2+
use crate::protocol::saas_rs::user::v1::generate_request::UsePaymentProvider;
3+
use crate::protocol::saas_rs::user::v1::{
4+
generate_request::{self, use_payment_provider::Provider},
5+
GenerateRequest,
6+
};
7+
use clap::{
8+
builder::PossibleValue,
9+
{Parser, ValueEnum},
10+
};
11+
12+
#[derive(Debug, Parser)]
13+
pub struct Opts {
14+
/// The identity provider
15+
#[arg(value_name = "provider", value_enum)]
16+
pub provider: Provider,
17+
}
18+
19+
pub async fn run(provider: Provider) -> Result<(), Box<dyn std::error::Error>> {
20+
let (project_id, snapshot) = do_generate_preflight(false).await?;
21+
let req = {
22+
GenerateRequest {
23+
project_id,
24+
snapshot: Some(snapshot),
25+
what: Some(generate_request::What::UsePaymentProvider(UsePaymentProvider {
26+
provider: provider as i32,
27+
})),
28+
}
29+
};
30+
do_generate(req).await
31+
}
32+
33+
impl ValueEnum for Provider {
34+
fn value_variants<'a>() -> &'a [Self] {
35+
&[Self::Stripe]
36+
}
37+
38+
fn to_possible_value(&self) -> Option<PossibleValue> {
39+
Some(PossibleValue::new(self.as_str_name()))
40+
}
41+
}

src/protocol/saas_rs.user.v1.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ pub struct GenerateRequest {
617617
pub project_id: ::prost::alloc::string::String,
618618
#[prost(oneof = "generate_request::Snapshot", tags = "2, 3")]
619619
pub snapshot: ::core::option::Option<generate_request::Snapshot>,
620-
#[prost(oneof = "generate_request::What", tags = "4, 5, 6, 7, 8, 9, 10, 11")]
620+
#[prost(oneof = "generate_request::What", tags = "4, 5, 6, 7, 8, 9, 10, 11, 12")]
621621
pub what: ::core::option::Option<generate_request::What>,
622622
}
623623
/// Nested message and enum types in `GenerateRequest`.
@@ -774,6 +774,47 @@ pub mod generate_request {
774774
}
775775
}
776776
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
777+
pub struct UsePaymentProvider {
778+
#[prost(enumeration = "use_payment_provider::Provider", tag = "1")]
779+
pub provider: i32,
780+
}
781+
/// Nested message and enum types in `UsePaymentProvider`.
782+
pub mod use_payment_provider {
783+
#[derive(
784+
Clone,
785+
Copy,
786+
Debug,
787+
PartialEq,
788+
Eq,
789+
Hash,
790+
PartialOrd,
791+
Ord,
792+
::prost::Enumeration
793+
)]
794+
#[repr(i32)]
795+
pub enum Provider {
796+
Stripe = 0,
797+
}
798+
impl Provider {
799+
/// String value of the enum field names used in the ProtoBuf definition.
800+
///
801+
/// The values are not transformed in any way and thus are considered stable
802+
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
803+
pub fn as_str_name(&self) -> &'static str {
804+
match self {
805+
Self::Stripe => "Stripe",
806+
}
807+
}
808+
/// Creates an enum from field names used in the ProtoBuf definition.
809+
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
810+
match value {
811+
"Stripe" => Some(Self::Stripe),
812+
_ => None,
813+
}
814+
}
815+
}
816+
}
817+
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
777818
pub struct UseStorageProvider {
778819
#[prost(enumeration = "use_storage_provider::Provider", tag = "1")]
779820
pub provider: i32,
@@ -854,6 +895,8 @@ pub mod generate_request {
854895
UseStorageProvider(UseStorageProvider),
855896
#[prost(message, tag = "11")]
856897
UseIdentityProvider(UseIdentityProvider),
898+
#[prost(message, tag = "12")]
899+
UsePaymentProvider(UsePaymentProvider),
857900
}
858901
}
859902
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]

src/protocol/saas_rs.user.v1.serde.rs

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13537,6 +13537,9 @@ impl serde::Serialize for GenerateRequest {
1353713537
generate_request::What::UseIdentityProvider(v) => {
1353813538
struct_ser.serialize_field("useIdentityProvider", v)?;
1353913539
}
13540+
generate_request::What::UsePaymentProvider(v) => {
13541+
struct_ser.serialize_field("usePaymentProvider", v)?;
13542+
}
1354013543
}
1354113544
}
1354213545
struct_ser.end()
@@ -13564,6 +13567,8 @@ impl<'de> serde::Deserialize<'de> for GenerateRequest {
1356413567
"useStorageProvider",
1356513568
"use_identity_provider",
1356613569
"useIdentityProvider",
13570+
"use_payment_provider",
13571+
"usePaymentProvider",
1356713572
];
1356813573

1356913574
#[allow(clippy::enum_variant_names)]
@@ -13579,6 +13584,7 @@ impl<'de> serde::Deserialize<'de> for GenerateRequest {
1357913584
Feature,
1358013585
UseStorageProvider,
1358113586
UseIdentityProvider,
13587+
UsePaymentProvider,
1358213588
__SkipField__,
1358313589
}
1358413590
impl<'de> serde::Deserialize<'de> for GeneratedField {
@@ -13612,6 +13618,7 @@ impl<'de> serde::Deserialize<'de> for GenerateRequest {
1361213618
"feature" => Ok(GeneratedField::Feature),
1361313619
"useStorageProvider" | "use_storage_provider" => Ok(GeneratedField::UseStorageProvider),
1361413620
"useIdentityProvider" | "use_identity_provider" => Ok(GeneratedField::UseIdentityProvider),
13621+
"usePaymentProvider" | "use_payment_provider" => Ok(GeneratedField::UsePaymentProvider),
1361513622
_ => Ok(GeneratedField::__SkipField__),
1361613623
}
1361713624
}
@@ -13710,6 +13717,13 @@ impl<'de> serde::Deserialize<'de> for GenerateRequest {
1371013717
return Err(serde::de::Error::duplicate_field("useIdentityProvider"));
1371113718
}
1371213719
what__ = map_.next_value::<::std::option::Option<_>>()?.map(generate_request::What::UseIdentityProvider)
13720+
;
13721+
}
13722+
GeneratedField::UsePaymentProvider => {
13723+
if what__.is_some() {
13724+
return Err(serde::de::Error::duplicate_field("usePaymentProvider"));
13725+
}
13726+
what__ = map_.next_value::<::std::option::Option<_>>()?.map(generate_request::What::UsePaymentProvider)
1371313727
;
1371413728
}
1371513729
GeneratedField::__SkipField__ => {
@@ -15065,6 +15079,171 @@ impl<'de> serde::Deserialize<'de> for generate_request::use_identity_provider::P
1506515079
deserializer.deserialize_any(GeneratedVisitor)
1506615080
}
1506715081
}
15082+
impl serde::Serialize for generate_request::UsePaymentProvider {
15083+
#[allow(deprecated)]
15084+
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
15085+
where
15086+
S: serde::Serializer,
15087+
{
15088+
use serde::ser::SerializeStruct;
15089+
let mut len = 0;
15090+
if true {
15091+
len += 1;
15092+
}
15093+
let mut struct_ser = serializer.serialize_struct("saas_rs.user.v1.GenerateRequest.UsePaymentProvider", len)?;
15094+
if true {
15095+
let v = generate_request::use_payment_provider::Provider::try_from(self.provider)
15096+
.map_err(|_| serde::ser::Error::custom(format!("Invalid variant {}", self.provider)))?;
15097+
struct_ser.serialize_field("provider", &v)?;
15098+
}
15099+
struct_ser.end()
15100+
}
15101+
}
15102+
impl<'de> serde::Deserialize<'de> for generate_request::UsePaymentProvider {
15103+
#[allow(deprecated)]
15104+
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
15105+
where
15106+
D: serde::Deserializer<'de>,
15107+
{
15108+
const FIELDS: &[&str] = &[
15109+
"provider",
15110+
];
15111+
15112+
#[allow(clippy::enum_variant_names)]
15113+
enum GeneratedField {
15114+
Provider,
15115+
__SkipField__,
15116+
}
15117+
impl<'de> serde::Deserialize<'de> for GeneratedField {
15118+
fn deserialize<D>(deserializer: D) -> std::result::Result<GeneratedField, D::Error>
15119+
where
15120+
D: serde::Deserializer<'de>,
15121+
{
15122+
struct GeneratedVisitor;
15123+
15124+
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
15125+
type Value = GeneratedField;
15126+
15127+
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15128+
write!(formatter, "expected one of: {:?}", &FIELDS)
15129+
}
15130+
15131+
#[allow(unused_variables)]
15132+
fn visit_str<E>(self, value: &str) -> std::result::Result<GeneratedField, E>
15133+
where
15134+
E: serde::de::Error,
15135+
{
15136+
match value {
15137+
"provider" => Ok(GeneratedField::Provider),
15138+
_ => Ok(GeneratedField::__SkipField__),
15139+
}
15140+
}
15141+
}
15142+
deserializer.deserialize_identifier(GeneratedVisitor)
15143+
}
15144+
}
15145+
struct GeneratedVisitor;
15146+
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
15147+
type Value = generate_request::UsePaymentProvider;
15148+
15149+
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15150+
formatter.write_str("struct saas_rs.user.v1.GenerateRequest.UsePaymentProvider")
15151+
}
15152+
15153+
fn visit_map<V>(self, mut map_: V) -> std::result::Result<generate_request::UsePaymentProvider, V::Error>
15154+
where
15155+
V: serde::de::MapAccess<'de>,
15156+
{
15157+
let mut provider__ = None;
15158+
while let Some(k) = map_.next_key()? {
15159+
match k {
15160+
GeneratedField::Provider => {
15161+
if provider__.is_some() {
15162+
return Err(serde::de::Error::duplicate_field("provider"));
15163+
}
15164+
provider__ = Some(map_.next_value::<generate_request::use_payment_provider::Provider>()? as i32);
15165+
}
15166+
GeneratedField::__SkipField__ => {
15167+
let _ = map_.next_value::<serde::de::IgnoredAny>()?;
15168+
}
15169+
}
15170+
}
15171+
Ok(generate_request::UsePaymentProvider {
15172+
provider: provider__.unwrap_or_default(),
15173+
})
15174+
}
15175+
}
15176+
deserializer.deserialize_struct("saas_rs.user.v1.GenerateRequest.UsePaymentProvider", FIELDS, GeneratedVisitor)
15177+
}
15178+
}
15179+
impl serde::Serialize for generate_request::use_payment_provider::Provider {
15180+
#[allow(deprecated)]
15181+
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
15182+
where
15183+
S: serde::Serializer,
15184+
{
15185+
let variant = match self {
15186+
Self::Stripe => "Stripe",
15187+
};
15188+
serializer.serialize_str(variant)
15189+
}
15190+
}
15191+
impl<'de> serde::Deserialize<'de> for generate_request::use_payment_provider::Provider {
15192+
#[allow(deprecated)]
15193+
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
15194+
where
15195+
D: serde::Deserializer<'de>,
15196+
{
15197+
const FIELDS: &[&str] = &[
15198+
"Stripe",
15199+
];
15200+
15201+
struct GeneratedVisitor;
15202+
15203+
impl<'de> serde::de::Visitor<'de> for GeneratedVisitor {
15204+
type Value = generate_request::use_payment_provider::Provider;
15205+
15206+
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15207+
write!(formatter, "expected one of: {:?}", &FIELDS)
15208+
}
15209+
15210+
fn visit_i64<E>(self, v: i64) -> std::result::Result<Self::Value, E>
15211+
where
15212+
E: serde::de::Error,
15213+
{
15214+
i32::try_from(v)
15215+
.ok()
15216+
.and_then(|x| x.try_into().ok())
15217+
.ok_or_else(|| {
15218+
serde::de::Error::invalid_value(serde::de::Unexpected::Signed(v), &self)
15219+
})
15220+
}
15221+
15222+
fn visit_u64<E>(self, v: u64) -> std::result::Result<Self::Value, E>
15223+
where
15224+
E: serde::de::Error,
15225+
{
15226+
i32::try_from(v)
15227+
.ok()
15228+
.and_then(|x| x.try_into().ok())
15229+
.ok_or_else(|| {
15230+
serde::de::Error::invalid_value(serde::de::Unexpected::Unsigned(v), &self)
15231+
})
15232+
}
15233+
15234+
fn visit_str<E>(self, value: &str) -> std::result::Result<Self::Value, E>
15235+
where
15236+
E: serde::de::Error,
15237+
{
15238+
match value {
15239+
"Stripe" => Ok(generate_request::use_payment_provider::Provider::Stripe),
15240+
_ => Err(serde::de::Error::unknown_variant(value, FIELDS)),
15241+
}
15242+
}
15243+
}
15244+
deserializer.deserialize_any(GeneratedVisitor)
15245+
}
15246+
}
1506815247
impl serde::Serialize for generate_request::UseStorageProvider {
1506915248
#[allow(deprecated)]
1507015249
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>

0 commit comments

Comments
 (0)