Skip to content

Commit 7b83792

Browse files
committed
feat: variation in configuration
1 parent b471ebf commit 7b83792

File tree

4 files changed

+174
-45
lines changed

4 files changed

+174
-45
lines changed

module/move/gspread/src/bin/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use clap::Parser;
33
use dotenv::dotenv;
44

55
use gspread::*;
6-
use gcore::Secret;
6+
use gcore::ApplicationSecret;
77
use gcore::client::Client;
88
use commands::
99
{
@@ -18,7 +18,7 @@ async fn main() -> Result< (), Box< dyn Error > >
1818
{
1919
dotenv().ok();
2020

21-
let secret = Secret::read();
21+
let secret = ApplicationSecret::read();
2222

2323
let client = Client::former()
2424
.token( &secret )

module/move/gspread/src/gcore/client.rs

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@ mod private
66
{
77

88
use reqwest;
9-
use yup_oauth2;
109
use former::Former;
1110

1211
use crate::*;
13-
use gcore::Secret;
1412
use gcore::error::{ Error, Result };
1513
use ser::
1614
{
@@ -101,41 +99,11 @@ mod private
10199
where
102100
Definition : former::FormerDefinition< Storage = ClientFormerStorage >,
103101
{
104-
pub async fn token( mut self, secret : &Secret ) -> Result< Self >
102+
pub async fn token< S >( mut self, secret : &S ) -> Result< Self > where S : gcore::Secret
105103
{
106104
debug_assert!( self.storage.token.is_none() );
107105

108-
let secret: yup_oauth2::ApplicationSecret = yup_oauth2::ApplicationSecret
109-
{
110-
client_id : secret.CLIENT_ID.clone(),
111-
auth_uri : secret.AUTH_URI.clone(),
112-
token_uri : secret.TOKEN_URI.clone(),
113-
client_secret : secret.CLIENT_SECRET.clone(),
114-
.. Default::default()
115-
};
116-
117-
let authenticator = yup_oauth2::InstalledFlowAuthenticator::builder(
118-
secret,
119-
yup_oauth2::InstalledFlowReturnMethod::HTTPRedirect,
120-
)
121-
.build()
122-
.await
123-
.map_err( | err | Error::AuthError( err.to_string() ) )?;
124-
125-
let scopes = vec!
126-
[
127-
"https://www.googleapis.com/auth/spreadsheets",
128-
"https://www.googleapis.com/auth/spreadsheets.readonly"
129-
];
130-
131-
let access_token = authenticator
132-
.token( &scopes )
133-
.await
134-
.map_err( | err | Error::AuthError( err.to_string() ) )?;
135-
136-
let token = access_token.token().unwrap();
137-
138-
self.storage.token = Some( token.to_string() );
106+
self.storage.token = Some( secret.get_token().await? );
139107

140108
Ok( self )
141109
}

module/move/gspread/src/gcore/secret.rs

Lines changed: 167 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,13 @@ mod private
6161
/// A type alias for `std::result::Result` with the error type `Error`.
6262
pub type Result< R > = std::result::Result< R, Error >;
6363

64-
/// # Secret
64+
pub trait Secret
65+
{
66+
#[ allow( async_fn_in_trait ) ]
67+
async fn get_token( &self ) -> gcore::error::Result< String >;
68+
}
69+
70+
/// # ApplicationSecret
6571
///
6672
/// A struct that represents configuration secrets loaded from a `.env` file.
6773
///
@@ -95,15 +101,15 @@ mod private
95101
/// ```
96102
#[ derive( Debug ) ]
97103
#[ allow( non_snake_case ) ]
98-
pub struct Secret
104+
pub struct ApplicationSecret
99105
{
100106
pub CLIENT_SECRET : String,
101107
pub CLIENT_ID: String,
102108
pub AUTH_URI : String,
103109
pub TOKEN_URI : String,
104110
}
105111

106-
impl Secret
112+
impl ApplicationSecret
107113
{
108114
#[ allow( non_snake_case ) ]
109115
pub fn load() -> Result< Self >
@@ -129,7 +135,127 @@ mod private
129135
Ok( config )
130136
}
131137

132-
pub fn read() -> Secret
138+
pub fn read() -> ApplicationSecret
139+
{
140+
Self::load().unwrap_or_else( | err |
141+
{
142+
let example = include_str!("../../.secret/readme.md");
143+
let explanation = format!
144+
(
145+
r#" = Lack of secrets
146+
147+
Failed to load secret or some its parameters.
148+
{err}
149+
150+
= Fix
151+
152+
Add missing secret to .env file in .secret directory. Example: MISSING_SECRET=YOUR_MISSING_SECRET
153+
154+
= More information
155+
156+
{example}
157+
"#
158+
);
159+
panic!( "{}", explanation );
160+
})
161+
}
162+
163+
pub fn get() -> &'static ApplicationSecret
164+
{
165+
static INSTANCE : OnceLock< ApplicationSecret > = OnceLock::new();
166+
INSTANCE.get_or_init( || Self::read() )
167+
}
168+
169+
}
170+
171+
impl Secret for ApplicationSecret
172+
{
173+
async fn get_token( &self ) -> gcore::error::Result< String >
174+
{
175+
let secret: yup_oauth2::ApplicationSecret = yup_oauth2::ApplicationSecret
176+
{
177+
client_id : self.CLIENT_ID.clone(),
178+
auth_uri : self.AUTH_URI.clone(),
179+
token_uri : self.TOKEN_URI.clone(),
180+
client_secret : self.CLIENT_SECRET.clone(),
181+
.. Default::default()
182+
};
183+
184+
let authenticator = yup_oauth2::InstalledFlowAuthenticator::builder(
185+
secret,
186+
yup_oauth2::InstalledFlowReturnMethod::HTTPRedirect,
187+
)
188+
.build()
189+
.await
190+
.map_err( | err | gcore::error::Error::AuthError( err.to_string() ) )?;
191+
192+
let scopes = vec!
193+
[
194+
"https://www.googleapis.com/auth/spreadsheets",
195+
"https://www.googleapis.com/auth/spreadsheets.readonly"
196+
];
197+
198+
let access_token = authenticator
199+
.token( &scopes )
200+
.await
201+
.map_err( | err | gcore::error::Error::AuthError( err.to_string() ) )?;
202+
203+
let token = access_token.token().unwrap();
204+
Ok( token.to_string() )
205+
}
206+
}
207+
208+
209+
/// # ServiceAccountSecret
210+
#[ derive( Debug ) ]
211+
#[ allow( non_snake_case ) ]
212+
pub struct ServiceAccountSecret
213+
{
214+
pub KEY_TYPE : String,
215+
pub PROJECT_ID: String,
216+
pub PRIVATE_KEY_ID : String,
217+
pub PRIVATE_KEY : String,
218+
pub CLIENT_EMAIL : String,
219+
pub CLIENT_ID : String,
220+
pub AUTH_URI : String,
221+
pub TOKEN_URI : String,
222+
pub AUTH_PROVIDER_X509_CERT_URL : String,
223+
pub CLIENT_X509_CERT_URL : String,
224+
}
225+
226+
impl ServiceAccountSecret
227+
{
228+
#[ allow( non_snake_case ) ]
229+
pub fn load() -> Result< Self >
230+
{
231+
let path = "./.secret/.env";
232+
233+
let r = dotenv::from_path( path );
234+
if let Err( ref err ) = r
235+
{
236+
if !matches!( err, dotenv::Error::Io(_) )
237+
{
238+
return Err( r.expect_err( &format!( "Failed to load {path}" ) ).into() );
239+
}
240+
}
241+
242+
let config = Self
243+
{
244+
KEY_TYPE : var( "GOOGLE_KEY_TYPE", None )?,
245+
PROJECT_ID : var( "GOOGLE_PROJECT_ID", None )?,
246+
PRIVATE_KEY_ID : var ( "GOOGLE_PRIVATE_KEY_ID", None )?,
247+
PRIVATE_KEY : var ( "GOOGLE_PRIVATE_KEY", None )?,
248+
CLIENT_EMAIL : var( "GOOGLE_CLIENT_EMAIL", None )?,
249+
CLIENT_ID : var( "GOOGLE_CLIENT_ID", None )?,
250+
AUTH_URI : var( "GOOGLE_AUTH_URI", None )?,
251+
TOKEN_URI : var( "GOOGLE_TOKEN_URI", None )?,
252+
AUTH_PROVIDER_X509_CERT_URL : var( "GOOGLE_AUTH_PROVIDER_X509_CERT_URL", None )?,
253+
CLIENT_X509_CERT_URL : var( "GOOGLE_CLIENT_X509_CERT_URL", None )?,
254+
};
255+
Ok( config )
256+
}
257+
258+
pub fn read() -> ServiceAccountSecret
133259
{
134260
Self::load().unwrap_or_else( | err |
135261
{
@@ -154,14 +280,47 @@ Add missing secret to .env file in .secret directory. Example: MISSING_SECRET=YO
154280
})
155281
}
156282

157-
pub fn get() -> &'static Secret
283+
pub fn get() -> &'static ServiceAccountSecret
158284
{
159-
static INSTANCE : OnceLock< Secret > = OnceLock::new();
285+
static INSTANCE : OnceLock< ServiceAccountSecret > = OnceLock::new();
160286
INSTANCE.get_or_init( || Self::read() )
161287
}
162288

163289
}
164290

291+
impl Secret for ServiceAccountSecret
292+
{
293+
async fn get_token( &self ) -> gcore::error::Result< String >
294+
{
295+
let key = yup_oauth2::ServiceAccountKey
296+
{
297+
key_type : Some( self.KEY_TYPE.clone() ),
298+
project_id : Some( self.PROJECT_ID.clone() ),
299+
private_key_id : Some( self.PRIVATE_KEY_ID.clone() ),
300+
private_key : self.PRIVATE_KEY.clone(),
301+
client_email : self.CLIENT_EMAIL.clone(),
302+
client_id : Some( self.CLIENT_ID.clone() ),
303+
auth_uri : Some( self.AUTH_URI.clone() ),
304+
token_uri : self.TOKEN_URI.clone(),
305+
auth_provider_x509_cert_url : Some( self.AUTH_PROVIDER_X509_CERT_URL.clone() ),
306+
client_x509_cert_url : Some( self.CLIENT_X509_CERT_URL.clone() ),
307+
};
308+
309+
let auth = yup_oauth2::ServiceAccountAuthenticator::builder( key )
310+
.build()
311+
.await
312+
.map_err( | err | gcore::error::Error::AuthError( err.to_string() ) )?;
313+
314+
let scopes = &[ "https://www.googleapis.com/auth/spreadsheets" ];
315+
316+
let token = auth.token( scopes ).await.map_err( | err | gcore::error::Error::AuthError( err.to_string() ) )?;
317+
318+
let token = token.token().unwrap();
319+
320+
Ok( token.to_string() )
321+
}
322+
}
323+
165324
/// # `var`
166325
///
167326
/// Retrieves the value of an environment variable, or returns a default value if the variable is not set.
@@ -235,5 +394,7 @@ crate::mod_interface!
235394
orphan use
236395
{
237396
Secret,
397+
ApplicationSecret,
398+
ServiceAccountSecret,
238399
};
239400
}

module/move/gspread/tests/inc/cells_tests.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use dotenv::dotenv;
22
use gspread::*;
33
use actions::gspread::{update_row, update_rows_by_custom_row_key, OnFail, OnFind};
4-
use gcore::Secret;
4+
use gcore::ApplicationSecret;
55
use gcore::client::Client;
66

77
/// # What
@@ -17,7 +17,7 @@ async fn test_update_row_should_work()
1717
{
1818
dotenv().ok();
1919

20-
let secret = Secret::read();
20+
let secret = ApplicationSecret::read();
2121

2222
let client = Client::former()
2323
.token( &secret )
@@ -66,7 +66,7 @@ async fn test_update_rows_by_custom_row_key_should_work()
6666
{
6767
dotenv().ok();
6868

69-
let secret = Secret::read();
69+
let secret = ApplicationSecret::read();
7070

7171
let client = Client::former()
7272
.token( &secret )

0 commit comments

Comments
 (0)