From b74d7b46f7cc0bcb9a1e31fe4f0b75f32635a495 Mon Sep 17 00:00:00 2001 From: Oghenemarho Orukele Date: Wed, 14 Aug 2024 20:20:18 +0200 Subject: [PATCH 1/2] finished data models for the send event route of terminal endpoint --- .github/workflows/rust.yml | 29 +++--------- README.md | 4 +- src/client.rs | 8 +++- src/endpoints/mod.rs | 2 + src/endpoints/subaccount.rs | 2 +- src/endpoints/terminal.rs | 40 ++++++++++++++++ src/endpoints/transaction.rs | 2 +- src/endpoints/transaction_split.rs | 2 +- src/models/mod.rs | 2 + src/models/terminal_model.rs | 74 ++++++++++++++++++++++++++++++ 10 files changed, 136 insertions(+), 29 deletions(-) create mode 100644 src/endpoints/terminal.rs create mode 100644 src/models/terminal_model.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8ce7e1a..655634b 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,7 +1,7 @@ name: Rust on: push: - branches: [ "main", "master" ] + branches: ["main", "master"] env: CARGO_TERM_COLOR: always PAYSTACK_API_KEY: ${{secrets.PAYSTACK_API_KEY}} @@ -12,25 +12,8 @@ jobs: build-and-test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - name: Build - run: cargo build --verbose - - name: Run tests - run: cargo test --verbose - coverage: - runs-on: ubuntu-latest - env: - CARGO_TERM_COLOR: always - steps: - - uses: actions/checkout@v4 - - name: Install Rust - run: rustup update stable - - name: Install cargo-llvm-cov - uses: taiki-e/install-action@cargo-llvm-cov - - name: Generate code coverage - run: cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 - with: - files: lcov.info - fail_ci_if_error: true \ No newline at end of file + - uses: actions/checkout@v3 + - name: Build + run: cargo build --verbose + - name: Run tests + run: cargo test --verbose diff --git a/README.md b/README.md index 826aa9b..dbf36be 100644 --- a/README.md +++ b/README.md @@ -94,8 +94,8 @@ async fn main() -> Result<(), PaystackAPIError> { ``` ### Examples -We provide some examples of use cases for the Paystack-rs crate. The examples are located in the [examples](examples) folder. +We provide some examples of use cases for the Paystack-rs crate. The examples are located in the [examples](examples) folder. ## Contributing @@ -105,13 +105,13 @@ We use Github actions to conduct CI/CD for the crate. It ensure that code is for as proper linting using `cargo clippy`, and finally run all the integration and unit test using `cargo test`. ### Crate module schematic diagram + A conceptual overview of the crate is illustrated below. This is to help improve the understanding of how the different parts of the crate interact with each other to work efficiently. The `PaystackClient` module is the central module of the crate and the best entry point to explore the different parts of the crate. ![Crate Schematic](docs/images/paystack-rs.png) - ## License Licensed under MIT license ([LICENSE-MIT](/LICENSE-MIT)). diff --git a/src/client.rs b/src/client.rs index 80ed181..ca82acf 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,7 +1,10 @@ //! Client //! ========= //! This file contains the Paystack API client, and it associated endpoints. -use crate::{HttpClient, SubaccountEndpoints, TransactionEndpoints, TransactionSplitEndpoints}; +use crate::{ + HttpClient, SubaccountEndpoints, TerminalEndpoints, TransactionEndpoints, + TransactionSplitEndpoints, +}; use std::sync::Arc; /// This is the entry level struct for the paystack API. @@ -13,6 +16,8 @@ pub struct PaystackClient { pub transaction_split: TransactionSplitEndpoints, /// Subaccount API route pub subaccount: SubaccountEndpoints, + /// Terminal API route + pub terminal: TerminalEndpoints, } impl PaystackClient { @@ -23,6 +28,7 @@ impl PaystackClient { transaction: TransactionEndpoints::new(api_key.clone(), Arc::clone(&http)), transaction_split: TransactionSplitEndpoints::new(api_key.clone(), Arc::clone(&http)), subaccount: SubaccountEndpoints::new(api_key.clone(), Arc::clone(&http)), + terminal: TerminalEndpoints::new(api_key.clone(), Arc::clone(&http)), } } } diff --git a/src/endpoints/mod.rs b/src/endpoints/mod.rs index 568ab91..652fe1f 100644 --- a/src/endpoints/mod.rs +++ b/src/endpoints/mod.rs @@ -1,8 +1,10 @@ pub mod subaccount; +pub mod terminal; pub mod transaction; pub mod transaction_split; // public re-export pub use subaccount::*; +pub use terminal::*; pub use transaction::*; pub use transaction_split::*; diff --git a/src/endpoints/subaccount.rs b/src/endpoints/subaccount.rs index f98d7de..4a3c38e 100644 --- a/src/endpoints/subaccount.rs +++ b/src/endpoints/subaccount.rs @@ -18,7 +18,7 @@ pub struct SubaccountEndpoints { } impl SubaccountEndpoints { - /// Constructor for the Subaccount object + /// Constructor pub fn new(key: String, http: Arc) -> SubaccountEndpoints { let base_url = String::from("https://api.paystack.co/subaccount"); SubaccountEndpoints { diff --git a/src/endpoints/terminal.rs b/src/endpoints/terminal.rs new file mode 100644 index 0000000..4317be2 --- /dev/null +++ b/src/endpoints/terminal.rs @@ -0,0 +1,40 @@ +//! Terminal +//! ======== +//! The Terminal API allows you to build delightful in-person payment experiences. + +use std::sync::Arc; + +use crate::{EventRequest, HttpClient, PaystackResult, SendEventResponseData}; + +/// A struct to hold all the functions of the terminal API endpoint +#[derive(Debug, Clone)] +pub struct TerminalEndpoints { + key: String, + base_url: String, + http: Arc, +} + +impl TerminalEndpoints { + /// Constructor + pub fn new(key: String, http: Arc) -> TerminalEndpoints { + let base_url = String::from("https://api.paystack.co/terminal"); + TerminalEndpoints { + key, + base_url, + http, + } + } + + /// Send an event from your application to the Paystack Terminal + /// + /// Takes in the following: + /// - `terminal_id`: The ID of the Terminal the event should be sent to. + /// - `EventRequest`: A struct containing the information of the event to send to the terminal. It is created with the `EventRequestBuilder`. + pub fn send_event( + &self, + terminal_id: String, + event_request: EventRequest, + ) -> PaystackResult { + todo!() + } +} diff --git a/src/endpoints/transaction.rs b/src/endpoints/transaction.rs index b3ecac5..102606e 100644 --- a/src/endpoints/transaction.rs +++ b/src/endpoints/transaction.rs @@ -21,7 +21,7 @@ pub struct TransactionEndpoints { } impl TransactionEndpoints { - /// Constructor for the transaction object + /// Constructor pub fn new(key: String, http: Arc) -> TransactionEndpoints { let base_url = String::from("https://api.paystack.co/transaction"); TransactionEndpoints { diff --git a/src/endpoints/transaction_split.rs b/src/endpoints/transaction_split.rs index ce19082..4431ae4 100644 --- a/src/endpoints/transaction_split.rs +++ b/src/endpoints/transaction_split.rs @@ -18,7 +18,7 @@ pub struct TransactionSplitEndpoints { } impl TransactionSplitEndpoints { - /// Constructor for the transaction object + /// Constructor pub fn new(key: String, http: Arc) -> TransactionSplitEndpoints { let base_url = String::from("https://api.paystack.co/split"); TransactionSplitEndpoints { diff --git a/src/models/mod.rs b/src/models/mod.rs index 96695a1..d8ec405 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -7,6 +7,7 @@ pub mod response; pub mod split; pub mod status; pub mod subaccount_model; +pub mod terminal_model; pub mod transaction_model; pub mod transaction_split_model; @@ -20,5 +21,6 @@ pub use response::*; pub use split::*; pub use status::*; pub use subaccount_model::*; +pub use terminal_model::*; pub use transaction_model::*; pub use transaction_split_model::*; diff --git a/src/models/terminal_model.rs b/src/models/terminal_model.rs new file mode 100644 index 0000000..7d17c7c --- /dev/null +++ b/src/models/terminal_model.rs @@ -0,0 +1,74 @@ +//! Terminal +//! ========== +//! This file contains the models and options for the Terminal endpoint of the Paystack + +use derive_builder::Builder; +use serde::{Deserialize, Serialize}; +use std::fmt; + +/// The request body to send an event from your application to the Paystack Terminal +#[derive(Debug, Clone, Builder, Serialize, Deserialize)] +pub struct EventRequest { + #[serde(rename = "type")] + pub event_type: EventType, + pub action: TerminalAction, + pub data: EventRequestData, +} + +/// The paramters needed to perform the specified action. +/// +/// For the invoice type, you need to pass the invoice id and offline reference: {id: invoice_id, reference: offline_reference}. +/// +/// For the transaction type, you can pass the transaction id: {id: transaction_id}, reference field can be `None` +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct EventRequestData { + pub id: String, + pub reference: Option, +} + +/// The type of event to push. +/// Paystack currently support `invoice` and `transaction` +#[derive(Debug, Serialize, Deserialize, Clone)] +pub enum EventType { + Invoice, + Transaction, +} + +/// The action the Terminal needs to perform. +/// +/// - For the `Invoice` type, the action can either be `Process` or `View`. +/// +/// - For the `Transaction` type, the action can either be `Process` or `Print`. +#[derive(Debug, Serialize, Deserialize, Clone)] +pub enum TerminalAction { + Process, + View, + Print, +} + +impl fmt::Display for TerminalAction { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let action = match self { + TerminalAction::Process => "process", + TerminalAction::Print => "print", + TerminalAction::View => "view", + }; + write!(f, "{}", action) + } +} + +impl fmt::Display for EventType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let event = match self { + EventType::Invoice => "invoice", + EventType::Transaction => "transaction", + }; + write!(f, "{}", event) + } +} + +/// Contains response data for the send event route in the terminal endpoint. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct SendEventResponseData { + pub id: String, +} From 0b4527f4c71e9edb28c1474471c17f8755ee6311 Mon Sep 17 00:00:00 2001 From: Oghenemarho Orukele Date: Mon, 9 Jun 2025 23:13:51 +0200 Subject: [PATCH 2/2] updated diagrams to use mermaid instead of a static one --- README.md | 39 ++++++++++++++++--- docs/images/paystack-rs.png | Bin 25079 -> 0 bytes docs/uml/paystack-rs.drawio | 72 ------------------------------------ src/http/base.rs | 1 - 4 files changed, 34 insertions(+), 78 deletions(-) delete mode 100644 docs/images/paystack-rs.png delete mode 100644 docs/uml/paystack-rs.drawio diff --git a/README.md b/README.md index dbf36be..c8c06e1 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ [![paystack-rs on docs.rs](https://docs.rs/paystack-rs/badge.svg)](https://docs.rs/paystack-rs) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) ->*NB: a core rewrite of the project is being carried out, the goal is to make the crate easier to maintain, -improve the performance, abstract certain features to improve flexibility, and support for both blocking and non-blocking -operations.* +> _NB: a core rewrite of the project is being carried out, the goal is to make the crate easier to maintain, +> improve the performance, abstract certain features to improve flexibility, and support for both blocking and non-blocking +> operations._ Convenient Rust bindings and types for the [Paystack](https://paystack.com) HTTP API aiming to support the entire API surface. Not the case? Please open an issue. I update the definitions on a weekly basis. @@ -68,7 +68,7 @@ async fn main() -> Result<(), PaystackAPIError> { let api_key = env::var("PAYSTACK_API_KEY").unwrap(); let client = PaystackClient::new(api_key); - + let email = "email@example.com".to_string(); let amount ="10_000".to_string(); let body = TransactionRequestBuilder::default() @@ -110,7 +110,36 @@ A conceptual overview of the crate is illustrated below. This is to help improve parts of the crate interact with each other to work efficiently. The `PaystackClient` module is the central module of the crate and the best entry point to explore the different parts of the crate. -![Crate Schematic](docs/images/paystack-rs.png) +```mermaid +--- +config: + layout: dagre + theme: default +--- +flowchart TD + subgraph subGraph0["HTTP Layer"] + HTTPClient["<Trait> HTTPClient"] + ReqwestClient["ReqwestClient"] + OtherClients["OtherClients"] + end + subgraph Core["Core"] + Models["Models"] + APIEndpoints["APIEndpoints"] + Macros["Macros"] + end + subgraph Types["Types"] + Response["Response"] + Request["Request"] + Error["Error"] + end + ReqwestClient --> HTTPClient + OtherClients --> HTTPClient + HTTPClient --> PaystackClient["PaystackClient"] + PaystackClient --> APIEndpoints + APIEndpoints --> Models + Macros --> Models & APIEndpoints + Models --> Response & Request & Error +``` ## License diff --git a/docs/images/paystack-rs.png b/docs/images/paystack-rs.png deleted file mode 100644 index bb20ceeea98938d2483ee6c9afd0181cab1d5ab9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25079 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/http/base.rs b/src/http/base.rs index ef266c2..a3655a0 100644 --- a/src/http/base.rs +++ b/src/http/base.rs @@ -13,7 +13,6 @@ pub type Query<'a> = Vec<(&'a str, &'a str)>; /// with their preferred HTTP client. /// To be as generic as possible, the U generic stands for the HTTP response. /// Ideally, it should be bounded to specific traits common in all response. -/// TODO: Bound the U generic to the appropriate traits. #[async_trait] pub trait HttpClient: Debug + Default + Clone + Send {