Skip to content

Commit

Permalink
Add get_terms_and_conditions_status graphql query (#80)
Browse files Browse the repository at this point in the history
* Add `get_terms_and_conditions_status` graphql query

* Add code review suggestions

* Apply suggestions from code review

Co-authored-by: Andrei <92177534+andrei-21@users.noreply.github.com>

* Validate service provider in response

---------

Co-authored-by: Andrei <92177534+andrei-21@users.noreply.github.com>
  • Loading branch information
dleutenegger and andrei-21 authored Dec 4, 2023
1 parent 0d76999 commit 2172768
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 59 deletions.
8 changes: 8 additions & 0 deletions graphql/schemas/operations.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ mutation AcceptTermsAndConditions($serviceProvider: String!) {
}
}

query GetTermsAndConditionsStatus($serviceProvider: ServiceProviderEnum!) {
get_terms_conditions_status(args: {service_provider: $serviceProvider}) {
serviceProvider
acceptedTerms
acceptDate
}
}

# Employee

query GetBusinessOwner($ownerWalletPubKeyId: uuid!) {
Expand Down
85 changes: 28 additions & 57 deletions graphql/schemas/schema_wallet_read.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ directive @cached(
refresh: Boolean! = false
) on QUERY

type AcceptTermsResponse {
acceptDate: DateTime
acceptedTerms: Boolean!
serviceProvider: ServiceProviderEnum!
}

input AcceptWalletPkRequestInput {
id: String!
}
Expand Down Expand Up @@ -47,6 +53,16 @@ type CreateBackupResponse {

scalar DateTime

input GetTermsConditionsStatusInputInput {
service_provider: ServiceProviderEnum
}

type GetTermsConditionsStatusResponse {
acceptDate: DateTime
acceptedTerms: Boolean!
serviceProvider: ServiceProviderEnum!
}

type MigrationBalanceResponse {
balanceAmountSat: BigInteger!
}
Expand Down Expand Up @@ -131,6 +147,15 @@ input RequestSucceededInput {
paymentReceivedAt: DateTime!
}

enum ServiceProviderEnum {
LIPA_WALLET
POCKET_EXCHANGE
}

input ServiceProviderInputInput {
service_provider: String
}

type SessionPermit {
accessToken: String
refreshToken: String
Expand Down Expand Up @@ -228,14 +253,6 @@ type WalletNode {
walletPubKeyId: String
}

input accept_terms_args {
pubkey_id: uuid
}

input accept_terms_conditions_args {
service_provider: String
}

"""
columns and relationships of "accepted_terms_conditions"
"""
Expand Down Expand Up @@ -815,55 +832,7 @@ enum cursor_ordering {

"""mutation root"""
type mutation_root {
"""
execute VOLATILE function "accept_terms" which returns "accepted_terms_conditions"
"""
accept_terms(
"""
input parameters for function "accept_terms"
"""
args: accept_terms_args!

"""distinct select on columns"""
distinct_on: [accepted_terms_conditions_select_column!]

"""limit the number of rows returned"""
limit: Int

"""skip the first n rows. Use only with order_by"""
offset: Int

"""sort the rows by one or more columns"""
order_by: [accepted_terms_conditions_order_by!]

"""filter the rows returned"""
where: accepted_terms_conditions_bool_exp
): accepted_terms_conditions

"""
execute VOLATILE function "accept_terms_conditions" which returns "accepted_terms_conditions"
"""
accept_terms_conditions(
"""
input parameters for function "accept_terms_conditions"
"""
args: accept_terms_conditions_args!

"""distinct select on columns"""
distinct_on: [accepted_terms_conditions_select_column!]

"""limit the number of rows returned"""
limit: Int

"""skip the first n rows. Use only with order_by"""
offset: Int

"""sort the rows by one or more columns"""
order_by: [accepted_terms_conditions_order_by!]

"""filter the rows returned"""
where: accepted_terms_conditions_bool_exp
): accepted_terms_conditions
accept_terms_conditions(args: ServiceProviderInputInput): AcceptTermsResponse
accept_wallet_acl_by_pk(pk_columns: AcceptWalletPkRequestInput!): WalletAcl
create_backup(encryptedBackup: String!, schemaName: String!, schemaVersion: String!): CreateBackupResponse

Expand Down Expand Up @@ -1080,6 +1049,7 @@ type query_root {

"""fetch data from the table: "channel_monitor" using primary key columns"""
channel_monitor_by_pk(channelId: bytea!, timestamp: timestamptz!, walletId: uuid!): channel_monitor
consumer_service_version: String

"""
fetch data from the table: "country"
Expand Down Expand Up @@ -1129,6 +1099,7 @@ type query_root {
"""ISO 4217"""
currencyCode: String!
): currency
get_terms_conditions_status(args: GetTermsConditionsStatusInputInput): GetTermsConditionsStatusResponse
migration_balance(nodePubKey: String): MigrationBalanceResponse
notification_service_version: String
payment_service_version: String
Expand Down
8 changes: 8 additions & 0 deletions graphql/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ pub struct RefreshSession;
)]
pub struct AcceptTermsAndConditions;

#[derive(GraphQLQuery)]
#[graphql(
schema_path = "schemas/schema_wallet_read.graphql",
query_path = "schemas/operations.graphql",
response_derives = "Debug"
)]
pub struct GetTermsAndConditionsStatus;

#[derive(GraphQLQuery)]
#[graphql(
schema_path = "schemas/schema_wallet_read.graphql",
Expand Down
15 changes: 15 additions & 0 deletions honey-badger/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ pub struct Auth {
token: Mutex<AdjustedToken>,
}

#[derive(Debug, PartialEq)]
pub struct TermsAndConditionsStatus {
pub accepted_at: Option<SystemTime>,
pub terms_and_conditions: TermsAndConditions,
}

impl Auth {
pub fn new(
backend_url: String,
Expand Down Expand Up @@ -83,6 +89,15 @@ impl Auth {
provider.accept_terms_and_conditions(token, terms)
}

pub fn get_terms_and_conditions_status(
&self,
terms: TermsAndConditions,
) -> Result<TermsAndConditionsStatus> {
let token = self.query_token()?;
let provider = self.provider.lock().unwrap();
provider.get_terms_and_conditions_status(token, terms)
}

fn get_token_if_valid(&self) -> Option<String> {
let now = SystemTime::now();
let token = self.token.lock().unwrap();
Expand Down
80 changes: 78 additions & 2 deletions honey-badger/src/provider.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use crate::secrets::KeyPair;
use crate::signing::sign;

use crate::TermsAndConditionsStatus;
use graphql::perro::{ensure, invalid_input, permanent_failure, runtime_error, OptionToError};
use graphql::reqwest::blocking::Client;
use graphql::schema::get_terms_and_conditions_status::ServiceProviderEnum;
use graphql::schema::*;
use graphql::{build_client, post_blocking};
use graphql::{build_client, perro, post_blocking};
use graphql::{errors::*, parse_from_rfc3339};
use log::info;
use std::time::SystemTime;
Expand All @@ -16,7 +18,7 @@ pub enum AuthLevel {
Employee,
}

#[derive(Debug)]
#[derive(Debug, PartialEq, Clone)]
pub enum TermsAndConditions {
Lipa,
Pocket,
Expand All @@ -32,6 +34,30 @@ impl From<TermsAndConditions> for String {
}
}

impl From<TermsAndConditions> for ServiceProviderEnum {
fn from(value: TermsAndConditions) -> Self {
match value {
TermsAndConditions::Lipa => ServiceProviderEnum::LIPA_WALLET,
TermsAndConditions::Pocket => ServiceProviderEnum::POCKET_EXCHANGE,
}
}
}

impl TryInto<TermsAndConditions> for ServiceProviderEnum {
type Error = perro::Error<GraphQlRuntimeErrorCode>;

fn try_into(self) -> std::result::Result<TermsAndConditions, Self::Error> {
match self {
ServiceProviderEnum::LIPA_WALLET => Ok(TermsAndConditions::Lipa),
ServiceProviderEnum::POCKET_EXCHANGE => Ok(TermsAndConditions::Pocket),
ServiceProviderEnum::Other(v) => runtime_error!(
GraphQlRuntimeErrorCode::CorruptData,
"Unknown service provider: {v:?}",
),
}
}
}

pub(crate) struct AuthProvider {
backend_url: String,
auth_level: AuthLevel,
Expand Down Expand Up @@ -113,6 +139,56 @@ impl AuthProvider {
Ok(())
}

pub fn get_terms_and_conditions_status(
&self,
access_token: String,
terms: TermsAndConditions,
) -> Result<TermsAndConditionsStatus> {
info!("Requesting T&C status ({terms:?})...");
ensure!(
self.auth_level == AuthLevel::Pseudonymous,
invalid_input(
"Requesting T&C status not supported for auth levels other than Pseudonymous"
)
);

let variables = get_terms_and_conditions_status::Variables {
service_provider: terms.clone().into(),
};
let client = build_client(Some(&access_token))?;
let data =
post_blocking::<GetTermsAndConditionsStatus>(&client, &self.backend_url, variables)?;

let terms_status = data.get_terms_conditions_status.ok_or_runtime_error(
GraphQlRuntimeErrorCode::RemoteServiceUnavailable,
"Couldn't fetch T&C status.",
)?;

let accepted_at = if terms_status.accepted_terms {
terms_status
.accept_date
.map(|date| parse_from_rfc3339(&date))
.transpose()?
} else {
None
};

let terms_and_conditions: TermsAndConditions = terms_status.service_provider.try_into()?;

ensure!(
terms_and_conditions.clone() == terms,
runtime_error(
GraphQlRuntimeErrorCode::CorruptData,
format!("Requested status of T&C {terms:?} received {terms_and_conditions:?}")
)
);

Ok(TermsAndConditionsStatus {
accepted_at,
terms_and_conditions,
})
}

fn run_auth_flow(&mut self) -> Result<(String, String)> {
let (access_token, refresh_token, wallet_pub_key_id) = self.start_basic_session()?;

Expand Down

0 comments on commit 2172768

Please sign in to comment.