From ad720187c5f3617e0a9c71cce819ce7b66f8295a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Djk=C3=A1=C5=A5o?= Date: Tue, 27 Feb 2024 17:50:48 +0100 Subject: [PATCH] reorganised into a workspace --- .env | 3 - .env.example | 9 +- .gitignore | 1 + Cargo.lock | 75 ++- Cargo.toml | 15 +- app logo template.xcf | Bin 0 -> 22381 bytes saleor-app-sdk/Cargo.toml | 20 + saleor-app-sdk/src/apl/env_apl.rs | 29 ++ saleor-app-sdk/src/apl/file_apl.rs | 34 ++ saleor-app-sdk/src/apl/mod.rs | 24 + saleor-app-sdk/src/apl/redis_apl.rs | 97 ++++ saleor-app-sdk/src/headers.rs | 6 + saleor-app-sdk/src/lib.rs | 40 ++ saleor-app-sdk/src/manifest.rs | 174 +++++++ saleor-app-sdk/src/webhooks.rs | 165 ++++++ saleor-app-template/Cargo.toml | 29 ++ saleor-app-template/public/logo.png | Bin 0 -> 24834 bytes {src => saleor-app-template/src}/app.rs | 7 +- {src => saleor-app-template/src}/config.rs | 5 +- {src => saleor-app-template/src}/main.rs | 50 +- .../src}/routes/manifest.rs | 6 +- saleor-app-template/src/routes/mod.rs | 35 ++ .../src}/routes/register.rs | 11 +- .../src}/routes/webhooks.rs | 0 src/routes/mod.rs | 17 - src/saleor.rs | 477 ------------------ 26 files changed, 783 insertions(+), 546 deletions(-) create mode 100644 app logo template.xcf create mode 100644 saleor-app-sdk/Cargo.toml create mode 100644 saleor-app-sdk/src/apl/env_apl.rs create mode 100644 saleor-app-sdk/src/apl/file_apl.rs create mode 100644 saleor-app-sdk/src/apl/mod.rs create mode 100644 saleor-app-sdk/src/apl/redis_apl.rs create mode 100644 saleor-app-sdk/src/headers.rs create mode 100644 saleor-app-sdk/src/lib.rs create mode 100644 saleor-app-sdk/src/manifest.rs create mode 100644 saleor-app-sdk/src/webhooks.rs create mode 100644 saleor-app-template/Cargo.toml create mode 100644 saleor-app-template/public/logo.png rename {src => saleor-app-template/src}/app.rs (92%) rename {src => saleor-app-template/src}/config.rs (88%) rename {src => saleor-app-template/src}/main.rs (60%) rename {src => saleor-app-template/src}/routes/manifest.rs (65%) create mode 100644 saleor-app-template/src/routes/mod.rs rename {src => saleor-app-template/src}/routes/register.rs (90%) rename {src => saleor-app-template/src}/routes/webhooks.rs (100%) delete mode 100644 src/routes/mod.rs delete mode 100644 src/saleor.rs diff --git a/.env b/.env index 6511cf4..f61a29f 100644 --- a/.env +++ b/.env @@ -1,6 +1,3 @@ -APP_AUTHOR="Djkáťo" -APP_DESCRIPTION="A simple rust app for doing many things" -APP_NAME="Rust test app" REQUIRED_SALEOR_VERSION="^3.13" SALEOR_APP_ID="dummy-saleor-app-rs" APP_API_BASE_URL="http://10.100.110.234:3000" diff --git a/.env.example b/.env.example index c4f27e6..f61a29f 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,6 @@ -APP_NAME="Rust test app" -REQUIRED_SALEOR_VERSION=">=3.11.7 <4" +REQUIRED_SALEOR_VERSION="^3.13" SALEOR_APP_ID="dummy-saleor-app-rs" -APP_API_BASE_URL="http://localhost:8000/graphql/" -APL="redis" -APL_URL="redis://redis:6379/2" +APP_API_BASE_URL="http://10.100.110.234:3000" +APL="Redis" +APL_URL="redis://localhost:6380/2" LOG_LEVEL="DEBUG" diff --git a/.gitignore b/.gitignore index ea8c4bf..fedaa2b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +.env diff --git a/Cargo.lock b/Cargo.lock index f7c13f4..b3888bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -134,6 +134,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + [[package]] name = "byteorder" version = "1.5.0" @@ -504,6 +510,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ce4ef31cda248bbdb6e6820603b82dfcd9e833db65a43e997a0ccec777d11fe" + [[package]] name = "httparse" version = "1.8.0" @@ -638,6 +650,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "miniz_oxide" version = "0.7.2" @@ -891,7 +913,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -933,7 +955,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] -name = "saleor-app-rs" +name = "saleor-app-sdk" +version = "0.1.0" +dependencies = [ + "anyhow", + "redis", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "saleor-app-template" version = "0.1.0" dependencies = [ "anyhow", @@ -942,9 +976,12 @@ dependencies = [ "dotenvy", "envy", "redis", + "saleor-app-sdk", "serde", "serde_json", "tokio", + "tower", + "tower-http", "tracing", "tracing-serde", "tracing-subscriber", @@ -1213,6 +1250,31 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +dependencies = [ + "bitflags 2.4.2", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "http-range-header", + "httpdate", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-layer" version = "0.3.2" @@ -1293,6 +1355,15 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.15" diff --git a/Cargo.toml b/Cargo.toml index a719d48..99bc689 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,10 @@ -[package] -name = "saleor-app-rs" -version = "0.1.0" -edition = "2021" +[workspace] +members = ["saleor-app-sdk", "saleor-app-template"] +resolver = "2" -[dependencies] +[workspace.dependencies] anyhow = "1.0.79" -#color-eyre = "0.6.2" cynic = "3.4.3" -#dotenvy_macro = "0.15.7" -#poem = {version = "2.0.0", features = ["redis-session"]} serde = "1.0.196" serde_json = "1.0.113" tokio = {version = "1.36.0", features = ["full"]} @@ -19,3 +15,6 @@ tracing-serde = "0.1.3" tracing-subscriber = { version = "0.3.18" } dotenvy = "0.15.7" axum = "0.7.4" +saleor-app-sdk = {path = "saleor-app-sdk"} +tower = { version = "0.4.13", features = ["util"] } +tower-http = { version = "0.5.2", features = ["fs", "trace"] } diff --git a/app logo template.xcf b/app logo template.xcf new file mode 100644 index 0000000000000000000000000000000000000000..2847cf61017491c789e795e4bf094fd541187e6f GIT binary patch literal 22381 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"] +version = "0.1.0" +edition = "2021" +description = "Unofficial Saleor App SDK like library, made to work with rust." +keywords = ["saleor", "sdk", "plugin"] +categories = [ "api-bindings", "web-programming::http-server"] +homepage = "https://github.com/djkato/saleor-app-rs-template" +repository = "https://github.com/djkato/saleor-app-rs-template" +documentation = "https://github.com/djkato/saleor-app-rs-template" +license = "MIT OR Apache-2.0" + +[dependencies] +anyhow.workspace = true +redis = { workspace=true, features = ["aio", "tokio-comp", "connection-manager"] } +serde.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true +serde_json.workspace = true diff --git a/saleor-app-sdk/src/apl/env_apl.rs b/saleor-app-sdk/src/apl/env_apl.rs new file mode 100644 index 0000000..caebdb3 --- /dev/null +++ b/saleor-app-sdk/src/apl/env_apl.rs @@ -0,0 +1,29 @@ +use super::APL; +use anyhow::Result; + +#[derive(Clone, Debug)] +/** +is not implemented yet! +*/ +pub struct EnvApl {} + +impl APL for EnvApl { + async fn set(&self, auth_data: crate::AuthData) -> Result<()> { + todo!() + } + async fn get(&self, saleor_api_url: &str) -> Result { + todo!() + } + async fn get_all(&self) -> Result> { + todo!() + } + async fn delete(&self, saleor_api_url: &str) -> Result<()> { + todo!() + } + async fn is_ready(&self) -> Result<()> { + todo!() + } + async fn is_configured(&self) -> Result<()> { + todo!() + } +} diff --git a/saleor-app-sdk/src/apl/file_apl.rs b/saleor-app-sdk/src/apl/file_apl.rs new file mode 100644 index 0000000..8923ed8 --- /dev/null +++ b/saleor-app-sdk/src/apl/file_apl.rs @@ -0,0 +1,34 @@ +use std::path::Path; + +use super::APL; +use anyhow::{bail, Result}; +use std::fs::{read, write}; + +#[derive(Clone, Debug)] +/** +is not implemented yet! +*/ +pub struct FileApl { + pub path: String, +} + +impl APL for FileApl { + async fn set(&self, auth_data: crate::AuthData) -> Result<()> { + todo!() + } + async fn get(&self, saleor_api_url: &str) -> Result { + todo!() + } + async fn get_all(&self) -> Result> { + todo!() + } + async fn delete(&self, saleor_api_url: &str) -> Result<()> { + todo!() + } + async fn is_ready(&self) -> Result<()> { + todo!() + } + async fn is_configured(&self) -> Result<()> { + todo!() + } +} diff --git a/saleor-app-sdk/src/apl/mod.rs b/saleor-app-sdk/src/apl/mod.rs new file mode 100644 index 0000000..4b72085 --- /dev/null +++ b/saleor-app-sdk/src/apl/mod.rs @@ -0,0 +1,24 @@ +pub mod env_apl; +pub mod file_apl; +pub mod redis_apl; + +use crate::AuthData; +use anyhow::Result; +use serde::{Deserialize, Serialize}; +use std::future::Future; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum AplType { + Redis, + File, + Env, +} + +pub trait APL: Sized + Send + Sync + Clone + std::fmt::Debug { + fn get(&self, saleor_api_url: &str) -> impl Future> + Send; + fn set(&self, auth_data: AuthData) -> impl Future> + Send; + fn delete(&self, saleor_api_url: &str) -> impl Future> + Send; + fn get_all(&self) -> impl Future>> + Send; + fn is_ready(&self) -> impl Future> + Send; + fn is_configured(&self) -> impl Future> + Send; +} diff --git a/saleor-app-sdk/src/apl/redis_apl.rs b/saleor-app-sdk/src/apl/redis_apl.rs new file mode 100644 index 0000000..6087bec --- /dev/null +++ b/saleor-app-sdk/src/apl/redis_apl.rs @@ -0,0 +1,97 @@ +use std::time::Duration; + +use redis::AsyncCommands; +use tracing::{debug, info}; + +use super::APL; +use crate::AuthData; +use anyhow::{bail, Result}; + +#[derive(Debug, Clone)] +pub struct RedisApl { + pub client: redis::Client, + pub app_api_base_url: String, +} + +impl APL for RedisApl { + async fn get(&self, saleor_api_url: &str) -> Result { + debug!(" get()"); + let mut conn = self.client.get_async_connection().await?; + let val: String = conn.get(self.prepare_key(saleor_api_url)).await?; + debug!("received {val}"); + let val: AuthData = serde_json::from_str(&val)?; + info!("sucessful get"); + debug!("parsed {val}"); + + Ok(val) + } + async fn set(&self, auth_data: AuthData) -> Result<()> { + debug!("set(), {}", auth_data); + let mut conn = self.client.get_async_connection().await?; + conn.set( + self.prepare_key(&auth_data.saleor_api_url), + serde_json::to_string(&auth_data)?, + ) + .await?; + info!("sucessful set"); + Ok(()) + } + async fn delete(&self, saleor_api_url: &str) -> Result<()> { + debug!("delete(), {}", saleor_api_url); + let mut conn = self.client.get_async_connection().await?; + let val: String = conn.get_del(self.prepare_key(saleor_api_url)).await?; + + debug!("sucessful delete(), {}", val); + info!("sucessful del"); + Ok(()) + } + async fn is_ready(&self) -> Result<()> { + debug!("is_ready()"); + let mut conn = self.client.get_async_connection().await?; + let val: String = redis::cmd("INFO") + .arg("server") + .query_async(&mut conn) + .await?; + + debug!("sucessful is_ready(), info: {}", val); + info!("sucessful is_ready"); + Ok(()) + } + async fn is_configured(&self) -> Result<()> { + debug!("is_configured()"); + let mut conn = self.client.get_async_connection().await?; + let val: String = redis::cmd("INFO") + .arg("server") + .query_async(&mut conn) + .await?; + + debug!("sucessful is_configured(), info: {}", val); + info!("sucessful is_configured"); + Ok(()) + } + async fn get_all(&self) -> Result> { + anyhow::bail!("Redis doens't support getall") + } +} + +impl RedisApl { + pub fn new(redis_url: String, app_api_base_url: String) -> Result { + let client = redis::Client::open(redis_url)?; + let mut conn = client.get_connection_with_timeout(Duration::from_secs(3))?; + let val: Result = + redis::cmd("INFO").arg("server").query(&mut conn); + + match val { + Ok(_) => Ok(Self { + client, + app_api_base_url, + }), + Err(e) => bail!("failed redis connection, {:?}", e), + } + } + pub fn prepare_key(&self, saleor_api_url: &str) -> String { + let key = format!("{}:{saleor_api_url}", self.app_api_base_url); + debug!("made key:'{}'", key); + key + } +} diff --git a/saleor-app-sdk/src/headers.rs b/saleor-app-sdk/src/headers.rs new file mode 100644 index 0000000..d95c7a8 --- /dev/null +++ b/saleor-app-sdk/src/headers.rs @@ -0,0 +1,6 @@ +pub const SALEOR_DOMAIN_HEADER: &str = "saleor-domain"; +pub const SALEOR_EVENT_HEADER: &str = "saleor-event"; +pub const SALEOR_SIGNATURE_HEADER: &str = "saleor-signature"; +pub const SALEOR_AUTHORIZATION_BEARER_HEADER: &str = "authorization-bearer"; +pub const SALEOR_API_URL_HEADER: &str = "saleor-api-url"; +pub const SALEOR_SCHEMA_VERSION: &str = "saleor-schema-version"; diff --git a/saleor-app-sdk/src/lib.rs b/saleor-app-sdk/src/lib.rs new file mode 100644 index 0000000..0fa5e1d --- /dev/null +++ b/saleor-app-sdk/src/lib.rs @@ -0,0 +1,40 @@ +pub mod apl; +pub mod headers; +pub mod manifest; +pub mod webhooks; + +use apl::APL; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AuthToken { + pub auth_token: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AuthData { + pub domain: Option, + pub token: String, + pub saleor_api_url: String, + pub app_id: String, + pub jwks: Option, +} +impl std::fmt::Display for AuthData { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "(domain:{}\ntoken:{}\nsaleor_api_url:{}\napp_id:{}\njwks:{})", + self.domain.clone().unwrap_or_default(), + self.token, + self.saleor_api_url, + self.app_id, + self.jwks.clone().unwrap_or_default() + ) + } +} + +#[derive(Debug, Clone)] +pub struct SaleorApp { + pub apl: A, +} diff --git a/saleor-app-sdk/src/manifest.rs b/saleor-app-sdk/src/manifest.rs new file mode 100644 index 0000000..952fe6a --- /dev/null +++ b/saleor-app-sdk/src/manifest.rs @@ -0,0 +1,174 @@ +use serde::{Deserialize, Serialize}; + +use crate::webhooks::WebhookManifest; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum AppPermission { + ManageUsers, + ManageStaff, + ImpersonateUser, + ManageObservability, + ManageCheckouts, + HandleCheckouts, + HandleTaxes, + ManageTaxes, + ManageChannels, + ManageDiscounts, + ManageGiftCard, + ManageMenus, + ManageOrders, + ManagePages, + ManagePageTypesAndAttributes, + HandlePayments, + ManagePlugins, + ManageProducts, + ManageProductTypesAndAttributes, + ManageShipping, + ManageSettings, + ManageTranslations, + ManageApps, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum AppExtensionMount { + ProductDetailsMoreActions, + ProductOverviewCreate, + ProductOverviewMoreActions, + NavigationCatalog, + NavigationOrders, + NavigationCustomers, + NavigationDiscounts, + NavigationTranslations, + NavigationPages, + OrderDetailsMoreActions, + OrderOverviewCreate, + OrderOverviewMoreActions, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum AppExtensionTarget { + Popup, + AppPage, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AppExtension { + /** Name which will be displayed in the dashboard */ + pub label: String, + /** the place where the extension will be mounted */ + pub mount: AppExtensionMount, + /** Method of presenting the interface + `POPUP` will present the interface in a modal overlay + `APP_PAGE` will navigate to the application page + @default `POPUP` + */ + pub target: AppExtensionTarget, + pub permissions: Vec, + /** URL of the view to display, + you can skip the domain and protocol when target is set to `APP_PAGE`, or when your manifest defines an `appUrl`. + + When target is set to `POPUP`, the url will be used to render an `