Compare commits
4 commits
27c039278c
...
a9b3b102d7
Author | SHA1 | Date | |
---|---|---|---|
a9b3b102d7 | |||
2a1922c918 | |||
178f3190ce | |||
242fd2510f |
22 changed files with 37016 additions and 292 deletions
70
Cargo.lock
generated
70
Cargo.lock
generated
|
@ -1,6 +1,6 @@
|
||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "addr2line"
|
name = "addr2line"
|
||||||
|
@ -952,7 +952,7 @@ version = "0.4.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "718f6cd8c54ae5249fd42b0c86639df0100b8a86eea2e5f1b915cde2e1481453"
|
checksum = "718f6cd8c54ae5249fd42b0c86639df0100b8a86eea2e5f1b915cde2e1481453"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap 2.5.0",
|
||||||
"lalrpop-util",
|
"lalrpop-util",
|
||||||
"logos",
|
"logos",
|
||||||
]
|
]
|
||||||
|
@ -1059,6 +1059,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1494,7 +1495,7 @@ dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
"indexmap",
|
"indexmap 2.5.0",
|
||||||
"slab",
|
"slab",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
|
@ -1566,6 +1567,12 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hkdf"
|
name = "hkdf"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
@ -1806,6 +1813,17 @@ dependencies = [
|
||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"hashbrown 0.12.3",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
@ -1814,6 +1832,7 @@ checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.14.5",
|
"hashbrown 0.14.5",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2024,7 +2043,7 @@ dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"getrandom 0.2.15",
|
"getrandom 0.2.15",
|
||||||
"html-escape",
|
"html-escape",
|
||||||
"indexmap",
|
"indexmap 2.5.0",
|
||||||
"itertools",
|
"itertools",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"leptos_reactive",
|
"leptos_reactive",
|
||||||
|
@ -2050,7 +2069,7 @@ checksum = "6cb53d4794240b684a2f4be224b84bee9e62d2abc498cf2bcd643cd565e01d96"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"camino",
|
"camino",
|
||||||
"indexmap",
|
"indexmap 2.5.0",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -2104,7 +2123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "25acc2f63cf91932013e400a95bf6e35e5d3dbb44a7b7e25a8e3057d12005b3b"
|
checksum = "25acc2f63cf91932013e400a95bf6e35e5d3dbb44a7b7e25a8e3057d12005b3b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"indexmap",
|
"indexmap 2.5.0",
|
||||||
"leptos",
|
"leptos",
|
||||||
"tracing",
|
"tracing",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
|
@ -2120,7 +2139,7 @@ dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"futures",
|
"futures",
|
||||||
"indexmap",
|
"indexmap 2.5.0",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"oco_ref",
|
"oco_ref",
|
||||||
"paste",
|
"paste",
|
||||||
|
@ -3358,9 +3377,10 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||||
name = "saleor-app-sdk"
|
name = "saleor-app-sdk"
|
||||||
version = "0.2.4"
|
version = "0.2.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"axum",
|
"axum",
|
||||||
|
"cynic",
|
||||||
|
"cynic-codegen",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
"envy",
|
"envy",
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
|
@ -3372,8 +3392,10 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde-wasm-bindgen",
|
"serde-wasm-bindgen",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"serde_with",
|
||||||
"strum 0.26.3",
|
"strum 0.26.3",
|
||||||
"strum_macros 0.26.4",
|
"strum_macros 0.26.4",
|
||||||
|
"surf",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
@ -3665,6 +3687,36 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_with"
|
||||||
|
version = "3.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.22.1",
|
||||||
|
"chrono",
|
||||||
|
"hex",
|
||||||
|
"indexmap 1.9.3",
|
||||||
|
"indexmap 2.5.0",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"serde_with_macros",
|
||||||
|
"time 0.3.36",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_with_macros"
|
||||||
|
version = "3.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d"
|
||||||
|
dependencies = [
|
||||||
|
"darling 0.20.10",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.77",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serial_test"
|
name = "serial_test"
|
||||||
version = "3.1.1"
|
version = "3.1.1"
|
||||||
|
@ -4401,7 +4453,7 @@ version = "0.22.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap 2.5.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
|
|
|
@ -80,14 +80,6 @@ hydrate = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# Defines a size-optimized profile for the WASM bundle in release mode
|
|
||||||
[profile.wasm-release]
|
|
||||||
inherits = "release"
|
|
||||||
opt-level = 'z'
|
|
||||||
lto = true
|
|
||||||
codegen-units = 1
|
|
||||||
panic = "abort"
|
|
||||||
|
|
||||||
[package.metadata.leptos]
|
[package.metadata.leptos]
|
||||||
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
|
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
|
||||||
output-name = "saleor-app-template-ui"
|
output-name = "saleor-app-template-ui"
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
use crate::error_template::{AppError, ErrorTemplate};
|
use crate::error_template::{AppError, ErrorTemplate};
|
||||||
use crate::routes::extensions::order_to_pdf::Pdf;
|
use crate::routes::extensions::order_to_pdf::OrderToPdf;
|
||||||
use crate::routes::home::Home;
|
use crate::routes::home::Home;
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
|
use leptos_dom::logging::{console_error, console_log};
|
||||||
use leptos_meta::*;
|
use leptos_meta::*;
|
||||||
use leptos_router::*;
|
use leptos_router::*;
|
||||||
|
use saleor_app_sdk::bridge::action::PayloadRequestPermissions;
|
||||||
|
use saleor_app_sdk::bridge::event::Event;
|
||||||
|
use saleor_app_sdk::bridge::{dispatch_event, listen_to_events, AppBridge};
|
||||||
|
use saleor_app_sdk::manifest::AppPermission;
|
||||||
|
|
||||||
#[derive(Params, PartialEq)]
|
#[derive(Params, PartialEq)]
|
||||||
pub struct UrlAppParams {
|
pub struct UrlAppParams {
|
||||||
|
@ -12,7 +17,70 @@ pub struct UrlAppParams {
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn App() -> impl IntoView {
|
pub fn App() -> impl IntoView {
|
||||||
// Provides context that manages stylesheets, titles, meta tags, etc.
|
let (bridge_read, bridge_set) = create_signal::<Option<AppBridge>>(None);
|
||||||
|
|
||||||
|
create_effect(move |_| match AppBridge::new(true) {
|
||||||
|
Ok(bridge) => bridge_set(Some(bridge)),
|
||||||
|
Err(e) => console_error(&format!("{:?}", e)),
|
||||||
|
});
|
||||||
|
|
||||||
|
create_effect(move |_| {
|
||||||
|
if let Err(e) = dispatch_event(saleor_app_sdk::bridge::action::Action::RequestPermissions(
|
||||||
|
PayloadRequestPermissions {
|
||||||
|
permissions: vec![AppPermission::ManageOrders, AppPermission::ManageProducts],
|
||||||
|
redirect_path: None,
|
||||||
|
},
|
||||||
|
)) {
|
||||||
|
console_error(&format!("{:?}", e));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
create_effect(move |_| {
|
||||||
|
listen_to_events(move |event_res| match event_res {
|
||||||
|
Ok(event) => match event {
|
||||||
|
Event::Handshake(payload) => {
|
||||||
|
if let Some(mut bridge) = bridge_read.get_untracked() {
|
||||||
|
bridge.state.token = Some(payload.token);
|
||||||
|
bridge.state.dashboard_version = payload.dashboard_version;
|
||||||
|
bridge.state.saleor_version = payload.saleor_version;
|
||||||
|
bridge_set(Some(bridge))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::Response(_) => {
|
||||||
|
// console_log(&format!("front::App: {:?}", payload.ok));
|
||||||
|
if let Some(mut bridge) = bridge_read.get_untracked() {
|
||||||
|
bridge.state.ready = true;
|
||||||
|
bridge_set(Some(bridge))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::Redirect(payload) => {
|
||||||
|
console_log(&payload.path);
|
||||||
|
}
|
||||||
|
Event::Theme(payload) => {
|
||||||
|
if let Some(mut bridge) = bridge_read.get_untracked() {
|
||||||
|
bridge.state.theme = payload.theme;
|
||||||
|
bridge_set(Some(bridge))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::LocaleChanged(payload) => {
|
||||||
|
if let Some(mut bridge) = bridge_read.get_untracked() {
|
||||||
|
bridge.state.locale = payload.locale;
|
||||||
|
bridge_set(Some(bridge))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::TokenRefreshed(payload) => {
|
||||||
|
if let Some(mut bridge) = bridge_read.get_untracked() {
|
||||||
|
bridge.state.token = Some(payload.token);
|
||||||
|
bridge_set(Some(bridge))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
console_error(&format!("front::App: {:?}", e));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
provide_meta_context();
|
provide_meta_context();
|
||||||
view! {
|
view! {
|
||||||
<Stylesheet id="leptos" href="/pkg/saleor-app-template-ui.css" />
|
<Stylesheet id="leptos" href="/pkg/saleor-app-template-ui.css" />
|
||||||
|
@ -29,7 +97,7 @@ pub fn App() -> impl IntoView {
|
||||||
<main class="p-4 md:p-8 md:px-16">
|
<main class="p-4 md:p-8 md:px-16">
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" view=Home />
|
<Route path="/" view=Home />
|
||||||
<Route path="/extensions/order_to_pdf" view=Pdf />
|
<Route path="/extensions/order_to_pdf" view=move || view!{<OrderToPdf bridge=bridge_read />}/>
|
||||||
</Routes>
|
</Routes>
|
||||||
</main>
|
</main>
|
||||||
</Router>
|
</Router>
|
||||||
|
|
|
@ -1,48 +1,29 @@
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
use leptos_dom::logging::{console_error, console_log};
|
use saleor_app_sdk::bridge::{action::PayloadRedirect, dispatch_event, AppBridge};
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Pdf() -> impl IntoView {
|
pub fn OrderToPdf(bridge: ReadSignal<Option<AppBridge>>) -> impl IntoView {
|
||||||
let bridge = create_effect(|_| {
|
|
||||||
use saleor_app_sdk::bridge::AppBridge;
|
|
||||||
use saleor_app_sdk::{
|
|
||||||
bridge::action::{Action, PayloadRequestPermissions},
|
|
||||||
manifest::AppPermission,
|
|
||||||
};
|
|
||||||
match AppBridge::new(true) {
|
|
||||||
Ok(mut app_bridge) => {
|
|
||||||
console_log("App Bridge connected");
|
|
||||||
let cb_handle = app_bridge
|
|
||||||
.listen_to_events(|event| match event {
|
|
||||||
Ok(event) => console_log(&format!("order_to_pdf: {:?}", event)),
|
|
||||||
Err(e) => console_error(&format!("order_to_pdf: {:?}", e)),
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
//TODO: imagine leaking memory on purpose xd
|
|
||||||
cb_handle.forget();
|
|
||||||
_ = app_bridge.dispatch_event(Action::RequestPermissions(
|
|
||||||
PayloadRequestPermissions {
|
|
||||||
permissions: vec![AppPermission::ManageOrders],
|
|
||||||
redirect_path: "".to_owned(),
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Err(e) => console_error(&format!("{:?}", e)),
|
|
||||||
}; // let mut bridge = bridge.unwrap();
|
|
||||||
|
|
||||||
// match bridge.dispatch_event(Event::Handshake(PayloadHanshake::default())) {
|
|
||||||
// Ok(ev) => {
|
|
||||||
// console_log(&format! {"{:?}",ev});
|
|
||||||
// }
|
|
||||||
// Err(e) => {
|
|
||||||
// console_log(&format! {"{:?}",e});
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// async fn temp(){}
|
|
||||||
// temp()
|
|
||||||
});
|
|
||||||
view! {
|
view! {
|
||||||
<h1>Yello!</h1>
|
<h1>Yello!</h1>
|
||||||
<p class="italic text-lg">r#"Loading AppBridge, please wait..."#</p>
|
|
||||||
|
{move || match bridge() {
|
||||||
|
Some(bridge) => {
|
||||||
|
match bridge.state.ready{
|
||||||
|
true => view!{
|
||||||
|
<div>
|
||||||
|
<button on:click=move |ev|{
|
||||||
|
dispatch_event(saleor_app_sdk::bridge::action::Action::Redirect(PayloadRedirect{
|
||||||
|
to: format!("/apps/{}/app", bridge.state.id),
|
||||||
|
new_context: None
|
||||||
|
})).expect("failed sending redirect action");
|
||||||
|
}>Settings</button>
|
||||||
|
<p class="italic text-lg">"token:"{bridge.state.token}</p>
|
||||||
|
</div>
|
||||||
|
}.into_view(),
|
||||||
|
false => view!{<p class="italic text-lg">r#"(bridge exists) Loading AppBridge, please wait..."#</p>}.into_view()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => view!{<p class="italic text-lg">r#"Loading AppBridge, please wait..."#</p>}.into_view()
|
||||||
|
}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "nightly-2024-06-20"
|
channel = "nightly-2024-11-13"
|
||||||
## Toggle to this one for sdk releases
|
## Toggle to this one for sdk releases
|
||||||
# channel = "stable"
|
# channel = "stable"
|
||||||
targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"]
|
targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"]
|
||||||
|
|
|
@ -12,7 +12,6 @@ documentation = "https://github.com/djkato/saleor-apps-rs"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = { workspace = true }
|
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
|
@ -50,6 +49,12 @@ wasm-bindgen = { workspace = true, optional = true }
|
||||||
serde-wasm-bindgen = { version = "0.6.5", optional = true }
|
serde-wasm-bindgen = { version = "0.6.5", optional = true }
|
||||||
# bus = { version = "2.4.1", optional = true }
|
# bus = { version = "2.4.1", optional = true }
|
||||||
|
|
||||||
|
## Needed for settings_manager
|
||||||
|
surf = { workspace = true, optional = true }
|
||||||
|
cynic = { workspace = true, optional = true, features = ["http-surf"] }
|
||||||
|
cynic-codegen.workspace = true
|
||||||
|
serde_with = { optional = true, version = "3.11.0" }
|
||||||
|
|
||||||
[dependencies.web-sys]
|
[dependencies.web-sys]
|
||||||
optional = true
|
optional = true
|
||||||
workspace = true
|
workspace = true
|
||||||
|
@ -65,6 +70,10 @@ features = [
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
||||||
|
## Needed for settings_manager
|
||||||
|
[build-dependencies]
|
||||||
|
cynic-codegen.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
middleware = [
|
middleware = [
|
||||||
|
@ -78,9 +87,5 @@ redis_apl = ["dep:redis"]
|
||||||
file_apl = []
|
file_apl = []
|
||||||
webhook_utils = ["dep:http"]
|
webhook_utils = ["dep:http"]
|
||||||
tracing = ["dep:tracing", "dep:tracing-subscriber"]
|
tracing = ["dep:tracing", "dep:tracing-subscriber"]
|
||||||
bridge = [
|
settings_manager = ["dep:cynic", "dep:surf", "dep:serde_with"]
|
||||||
"dep:wasm-bindgen",
|
bridge = ["dep:wasm-bindgen", "dep:serde-wasm-bindgen", "dep:web-sys"]
|
||||||
# "dep:bus",
|
|
||||||
"dep:serde-wasm-bindgen",
|
|
||||||
"dep:web-sys",
|
|
||||||
]
|
|
||||||
|
|
7
sdk/build.rs
Normal file
7
sdk/build.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
fn main() {
|
||||||
|
cynic_codegen::register_schema("saleor")
|
||||||
|
.from_sdl_file("schema.graphql")
|
||||||
|
.unwrap()
|
||||||
|
.as_default()
|
||||||
|
.unwrap();
|
||||||
|
}
|
36207
sdk/schema.graphql
Normal file
36207
sdk/schema.graphql
Normal file
File diff suppressed because it is too large
Load diff
|
@ -6,7 +6,6 @@ use std::{
|
||||||
use crate::AuthData;
|
use crate::AuthData;
|
||||||
|
|
||||||
use super::APL;
|
use super::APL;
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
@ -19,9 +18,19 @@ pub struct FileApl {
|
||||||
pub path: String,
|
pub path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum FileAplError {
|
||||||
|
#[error("Error during an IO file operation, {0}")]
|
||||||
|
IoError(#[from] std::io::Error),
|
||||||
|
#[error("Failed parsing from/to json, {0}")]
|
||||||
|
SerdeJsonDeError(#[from] serde_json::Error),
|
||||||
|
#[error("Can't find requested key in hashmap")]
|
||||||
|
MissingKey,
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl APL for FileApl {
|
impl APL<FileAplError> for FileApl {
|
||||||
async fn set(&self, auth_data: crate::AuthData) -> Result<()> {
|
async fn set(&self, auth_data: crate::AuthData) -> Result<(), FileAplError> {
|
||||||
let path = std::path::Path::new(&self.path);
|
let path = std::path::Path::new(&self.path);
|
||||||
debug!("reading from {:?}", &path);
|
debug!("reading from {:?}", &path);
|
||||||
let mut auths: FileStructure;
|
let mut auths: FileStructure;
|
||||||
|
@ -37,24 +46,24 @@ impl APL for FileApl {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get(&self, saleor_api_url: &str) -> Result<crate::AuthData> {
|
async fn get(&self, saleor_api_url: &str) -> Result<crate::AuthData, FileAplError> {
|
||||||
let path = std::path::Path::new(&self.path);
|
let path = std::path::Path::new(&self.path);
|
||||||
debug!("reading from {:?}", &path);
|
debug!("reading from {:?}", &path);
|
||||||
let auth_data: FileStructure = serde_json::from_str(&std::fs::read_to_string(path)?)?;
|
let auth_data: FileStructure = serde_json::from_str(&std::fs::read_to_string(path)?)?;
|
||||||
auth_data
|
auth_data
|
||||||
.get(saleor_api_url)
|
.get(saleor_api_url)
|
||||||
.cloned()
|
.cloned()
|
||||||
.ok_or(anyhow!("AuthData for {saleor_api_url} not found"))
|
.ok_or(FileAplError::MissingKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_all(&self) -> Result<Vec<crate::AuthData>> {
|
async fn get_all(&self) -> Result<Vec<crate::AuthData>, FileAplError> {
|
||||||
let path = std::path::Path::new(&self.path);
|
let path = std::path::Path::new(&self.path);
|
||||||
debug!("reading from {:?}", &path);
|
debug!("reading from {:?}", &path);
|
||||||
let auth_data: FileStructure = serde_json::from_str(&std::fs::read_to_string(path)?)?;
|
let auth_data: FileStructure = serde_json::from_str(&std::fs::read_to_string(path)?)?;
|
||||||
Ok(auth_data.0.values().cloned().collect())
|
Ok(auth_data.0.values().cloned().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn delete(&self, saleor_api_url: &str) -> Result<()> {
|
async fn delete(&self, saleor_api_url: &str) -> Result<(), FileAplError> {
|
||||||
let path = std::path::Path::new(&self.path);
|
let path = std::path::Path::new(&self.path);
|
||||||
debug!("reading from {:?}", &path);
|
debug!("reading from {:?}", &path);
|
||||||
let mut auths: FileStructure = serde_json::from_str(&std::fs::read_to_string(path)?)?;
|
let mut auths: FileStructure = serde_json::from_str(&std::fs::read_to_string(path)?)?;
|
||||||
|
@ -65,11 +74,11 @@ impl APL for FileApl {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn is_ready(&self) -> Result<()> {
|
async fn is_ready(&self) -> Result<(), FileAplError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn is_configured(&self) -> Result<()> {
|
async fn is_configured(&self) -> Result<(), FileAplError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ pub mod file_apl;
|
||||||
pub mod redis_apl;
|
pub mod redis_apl;
|
||||||
|
|
||||||
use crate::AuthData;
|
use crate::AuthData;
|
||||||
use anyhow::Result;
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -15,11 +14,11 @@ pub enum AplType {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait APL: Send + Sync + std::fmt::Debug {
|
pub trait APL<E>: Send + Sync + std::fmt::Debug {
|
||||||
async fn get(&self, saleor_api_url: &str) -> Result<AuthData>;
|
async fn get(&self, saleor_api_url: &str) -> Result<AuthData, E>;
|
||||||
async fn set(&self, auth_data: AuthData) -> Result<()>;
|
async fn set(&self, auth_data: AuthData) -> Result<(), E>;
|
||||||
async fn delete(&self, saleor_api_url: &str) -> Result<()>;
|
async fn delete(&self, saleor_api_url: &str) -> Result<(), E>;
|
||||||
async fn get_all(&self) -> Result<Vec<AuthData>>;
|
async fn get_all(&self) -> Result<Vec<AuthData>, E>;
|
||||||
async fn is_ready(&self) -> Result<()>;
|
async fn is_ready(&self) -> Result<(), E>;
|
||||||
async fn is_configured(&self) -> Result<()>;
|
async fn is_configured(&self) -> Result<(), E>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use redis::AsyncCommands;
|
use redis::{AsyncCommands, RedisError};
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, info};
|
||||||
|
|
||||||
use super::APL;
|
use super::APL;
|
||||||
use crate::AuthData;
|
use crate::AuthData;
|
||||||
use anyhow::{bail, Result};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RedisApl {
|
pub struct RedisApl {
|
||||||
|
@ -14,9 +13,19 @@ pub struct RedisApl {
|
||||||
pub app_api_base_url: String,
|
pub app_api_base_url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum RedisAplError {
|
||||||
|
#[error("Error during redis operation, {0}")]
|
||||||
|
RedisError(#[from] RedisError),
|
||||||
|
#[error("Failed parsing from/to json, {0}")]
|
||||||
|
SerdeJsonDeError(#[from] serde_json::Error),
|
||||||
|
#[error("RedisAPL doesn't support requested feature: {0}")]
|
||||||
|
NotSupported(String),
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl APL for RedisApl {
|
impl APL<RedisAplError> for RedisApl {
|
||||||
async fn get(&self, saleor_api_url: &str) -> Result<AuthData> {
|
async fn get(&self, saleor_api_url: &str) -> Result<AuthData, RedisAplError> {
|
||||||
debug!("get()");
|
debug!("get()");
|
||||||
let mut conn = self.client.get_multiplexed_async_connection().await?;
|
let mut conn = self.client.get_multiplexed_async_connection().await?;
|
||||||
let val: String = conn.get(self.prepare_key(saleor_api_url)).await?;
|
let val: String = conn.get(self.prepare_key(saleor_api_url)).await?;
|
||||||
|
@ -25,7 +34,7 @@ impl APL for RedisApl {
|
||||||
|
|
||||||
Ok(val)
|
Ok(val)
|
||||||
}
|
}
|
||||||
async fn set(&self, auth_data: AuthData) -> Result<()> {
|
async fn set(&self, auth_data: AuthData) -> Result<(), RedisAplError> {
|
||||||
debug!("set()");
|
debug!("set()");
|
||||||
let mut conn = self.client.get_multiplexed_async_connection().await?;
|
let mut conn = self.client.get_multiplexed_async_connection().await?;
|
||||||
conn.set::<_, _, String>(
|
conn.set::<_, _, String>(
|
||||||
|
@ -36,7 +45,7 @@ impl APL for RedisApl {
|
||||||
info!("sucessful set");
|
info!("sucessful set");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn delete(&self, saleor_api_url: &str) -> Result<()> {
|
async fn delete(&self, saleor_api_url: &str) -> Result<(), RedisAplError> {
|
||||||
debug!("delete(), {}", saleor_api_url);
|
debug!("delete(), {}", saleor_api_url);
|
||||||
let mut conn = self.client.get_multiplexed_async_connection().await?;
|
let mut conn = self.client.get_multiplexed_async_connection().await?;
|
||||||
let val: String = conn.get_del(self.prepare_key(saleor_api_url)).await?;
|
let val: String = conn.get_del(self.prepare_key(saleor_api_url)).await?;
|
||||||
|
@ -45,7 +54,7 @@ impl APL for RedisApl {
|
||||||
info!("sucessful del");
|
info!("sucessful del");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn is_ready(&self) -> Result<()> {
|
async fn is_ready(&self) -> Result<(), RedisAplError> {
|
||||||
debug!("is_ready()");
|
debug!("is_ready()");
|
||||||
let mut conn = self.client.get_multiplexed_async_connection().await?;
|
let mut conn = self.client.get_multiplexed_async_connection().await?;
|
||||||
let val: String = redis::cmd("INFO")
|
let val: String = redis::cmd("INFO")
|
||||||
|
@ -57,7 +66,7 @@ impl APL for RedisApl {
|
||||||
info!("sucessful is_ready");
|
info!("sucessful is_ready");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn is_configured(&self) -> Result<()> {
|
async fn is_configured(&self) -> Result<(), RedisAplError> {
|
||||||
debug!("is_configured()");
|
debug!("is_configured()");
|
||||||
let mut conn = self.client.get_multiplexed_async_connection().await?;
|
let mut conn = self.client.get_multiplexed_async_connection().await?;
|
||||||
let val: String = redis::cmd("INFO")
|
let val: String = redis::cmd("INFO")
|
||||||
|
@ -69,13 +78,15 @@ impl APL for RedisApl {
|
||||||
info!("sucessful is_configured");
|
info!("sucessful is_configured");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn get_all(&self) -> Result<Vec<AuthData>> {
|
async fn get_all(&self) -> Result<Vec<AuthData>, RedisAplError> {
|
||||||
anyhow::bail!("Redis doens't support getall")
|
Err(RedisAplError::NotSupported(
|
||||||
|
"Redis doens't support getall".to_owned(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RedisApl {
|
impl RedisApl {
|
||||||
pub fn new(redis_url: &str, app_api_base_url: &str) -> Result<Self> {
|
pub fn new(redis_url: &str, app_api_base_url: &str) -> Result<Self, RedisAplError> {
|
||||||
debug!("creating redis apl with {redis_url}...");
|
debug!("creating redis apl with {redis_url}...");
|
||||||
let client = redis::Client::open(redis_url)?;
|
let client = redis::Client::open(redis_url)?;
|
||||||
let mut conn = client.get_connection_with_timeout(Duration::from_secs(3))?;
|
let mut conn = client.get_connection_with_timeout(Duration::from_secs(3))?;
|
||||||
|
@ -87,7 +98,7 @@ impl RedisApl {
|
||||||
client,
|
client,
|
||||||
app_api_base_url: app_api_base_url.to_owned(),
|
app_api_base_url: app_api_base_url.to_owned(),
|
||||||
}),
|
}),
|
||||||
Err(e) => bail!("failed redis connection, {:?}", e),
|
Err(e) => Err(e.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn prepare_key(&self, saleor_api_url: &str) -> String {
|
pub fn prepare_key(&self, saleor_api_url: &str) -> String {
|
||||||
|
|
|
@ -2,6 +2,9 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::manifest::AppPermission;
|
use crate::manifest::AppPermission;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Actions are what the dashboard receives and app sends on `window.parent`
|
||||||
|
*/
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
#[serde(tag = "type", content = "payload")]
|
#[serde(tag = "type", content = "payload")]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
@ -16,7 +19,8 @@ pub enum Action {
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct PayloadRequestPermissions {
|
pub struct PayloadRequestPermissions {
|
||||||
pub permissions: Vec<AppPermission>,
|
pub permissions: Vec<AppPermission>,
|
||||||
pub redirect_path: String,
|
// #[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub redirect_path: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug, Default)]
|
#[derive(Deserialize, Serialize, Debug, Default)]
|
||||||
|
|
|
@ -1,67 +1,11 @@
|
||||||
use crate::{locales::LocaleCode, manifest::AppPermission};
|
use crate::manifest::{AppPermission, LocaleCode};
|
||||||
|
|
||||||
use super::ThemeType;
|
use super::ThemeType;
|
||||||
// use bus::{Bus, BusReader};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
// use strum_macros::EnumIter;
|
|
||||||
// use web_sys::js_sys::Object;
|
|
||||||
|
|
||||||
// pub struct EventChannels {
|
|
||||||
// pub handshake: Bus<PayloadHanshake>,
|
|
||||||
// pub response: Bus<PayloadResponse>,
|
|
||||||
// pub redirect: Bus<PayloadRedirect>,
|
|
||||||
// pub theme: Bus<PayloadTheme>,
|
|
||||||
// pub locale_changed: Bus<PayloadLocaleChanged>,
|
|
||||||
// pub token_refreshed: Bus<PayloadTokenRefreshed>,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl EventChannels {
|
|
||||||
// pub fn new() -> Self {
|
|
||||||
// Self {
|
|
||||||
// handshake: Bus::new(10),
|
|
||||||
// response: Bus::new(10),
|
|
||||||
// redirect: Bus::new(10),
|
|
||||||
// theme: Bus::new(10),
|
|
||||||
// locale_changed: Bus::new(10),
|
|
||||||
// token_refreshed: Bus::new(10),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pub fn subscribe_handshake(&mut self) -> BusReader<PayloadHanshake> {
|
|
||||||
// self.handshake.add_rx()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pub fn subscribe_response(&mut self) -> BusReader<PayloadResponse> {
|
|
||||||
// self.response.add_rx()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pub fn subscribe_redirect(&mut self) -> BusReader<PayloadRedirect> {
|
|
||||||
// self.redirect.add_rx()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pub fn subscribe_theme(&mut self) -> BusReader<PayloadTheme> {
|
|
||||||
// self.theme.add_rx()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pub fn subscribe_locale_changed(&mut self) -> BusReader<PayloadLocaleChanged> {
|
|
||||||
// self.locale_changed.add_rx()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pub fn subscribe_token_refreshed(&mut self) -> BusReader<PayloadTokenRefreshed> {
|
|
||||||
// self.token_refreshed.add_rx()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[derive(EnumIter, Debug)]
|
|
||||||
// pub enum EventType {
|
|
||||||
// Handshake,
|
|
||||||
// Response,
|
|
||||||
// Redirect,
|
|
||||||
// Theme,
|
|
||||||
// LocaleChanged,
|
|
||||||
// TokenRefreshed,
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Events are what the dashboard sends and app receives on `window`
|
||||||
|
*/
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
#[serde(tag = "type", content = "payload")]
|
#[serde(tag = "type", content = "payload")]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
@ -103,7 +47,7 @@ pub enum NotificationStatus {
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct PayloadHanshake {
|
pub struct PayloadHanshake {
|
||||||
pub token: String,
|
pub token: String,
|
||||||
pub version: f32,
|
pub version: i32,
|
||||||
pub saleor_version: Option<String>,
|
pub saleor_version: Option<String>,
|
||||||
pub dashboard_version: Option<String>,
|
pub dashboard_version: Option<String>,
|
||||||
}
|
}
|
||||||
|
@ -118,8 +62,7 @@ pub struct PayloadResponse {
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct PayloadRedirect {
|
pub struct PayloadRedirect {
|
||||||
pub to: String,
|
pub path: String,
|
||||||
pub new_context: Option<bool>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug, Default)]
|
#[derive(Deserialize, Serialize, Debug, Default)]
|
||||||
|
|
|
@ -8,11 +8,12 @@ use serde::{Deserialize, Serialize};
|
||||||
use strum_macros::{EnumString, IntoStaticStr};
|
use strum_macros::{EnumString, IntoStaticStr};
|
||||||
use wasm_bindgen::{closure::Closure, JsCast, JsValue};
|
use wasm_bindgen::{closure::Closure, JsCast, JsValue};
|
||||||
|
|
||||||
use crate::{locales::LocaleCode, manifest::AppPermission};
|
use crate::manifest::{AppPermission, LocaleCode};
|
||||||
|
|
||||||
use self::event::Event;
|
use self::event::Event;
|
||||||
use web_sys::{console, js_sys::JSON};
|
use web_sys::{console, js_sys::JSON};
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone)]
|
||||||
pub struct AppBridge {
|
pub struct AppBridge {
|
||||||
pub state: AppBridgeState,
|
pub state: AppBridgeState,
|
||||||
pub referer_origin: Option<String>,
|
pub referer_origin: Option<String>,
|
||||||
|
@ -24,7 +25,7 @@ pub struct AppBridge {
|
||||||
auto_notify_ready: bool,
|
auto_notify_ready: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug, Clone)]
|
||||||
pub struct AppBridgeState {
|
pub struct AppBridgeState {
|
||||||
pub token: Option<String>,
|
pub token: Option<String>,
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
@ -84,7 +85,7 @@ impl AppBridgeState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug, Clone)]
|
||||||
pub struct AppBridgeUser {
|
pub struct AppBridgeUser {
|
||||||
/**
|
/**
|
||||||
* Original permissions of the user that is using the app.
|
* Original permissions of the user that is using the app.
|
||||||
|
@ -108,7 +109,7 @@ pub enum AppIframeParams {
|
||||||
Locale,
|
Locale,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, EnumString)]
|
#[derive(Debug, Serialize, Deserialize, EnumString, Clone)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum ThemeType {
|
pub enum ThemeType {
|
||||||
Light,
|
Light,
|
||||||
|
@ -142,7 +143,7 @@ impl AppBridge {
|
||||||
console::log_1(&"Referrer origin is none".into());
|
console::log_1(&"Referrer origin is none".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut bridge = Self {
|
let bridge = Self {
|
||||||
auto_notify_ready,
|
auto_notify_ready,
|
||||||
state: match AppBridgeState::from_window() {
|
state: match AppBridgeState::from_window() {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
|
@ -151,19 +152,19 @@ impl AppBridge {
|
||||||
referer_origin: referrer,
|
referer_origin: referrer,
|
||||||
};
|
};
|
||||||
if bridge.auto_notify_ready {
|
if bridge.auto_notify_ready {
|
||||||
bridge.notify_ready()?;
|
dispatch_event(Action::NotifyReady("".into()))?;
|
||||||
}
|
}
|
||||||
Ok(bridge)
|
Ok(bridge)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* make sure to keep the returned closure handle safe, once it deallocs events will no longer
|
* make sure to keep the returned closure handle safe, once it deallocs events will no longer
|
||||||
* trigger
|
* trigger
|
||||||
*/
|
*/
|
||||||
pub fn listen_to_events(
|
pub fn listen_to_events(
|
||||||
&mut self,
|
|
||||||
mut on_event: impl FnMut(Result<Event, serde_wasm_bindgen::Error>) + 'static,
|
mut on_event: impl FnMut(Result<Event, serde_wasm_bindgen::Error>) + 'static,
|
||||||
) -> Result<Closure<dyn FnMut(JsValue)>, AppBridgeError> {
|
) -> Result<Closure<dyn FnMut(JsValue)>, AppBridgeError> {
|
||||||
let window = web_sys::window().ok_or(AppBridgeError::WindowIsUndefined)?;
|
let window = web_sys::window().ok_or(AppBridgeError::WindowIsUndefined)?;
|
||||||
let cb = Closure::wrap(Box::new(move |e: JsValue| {
|
let cb = Closure::wrap(Box::new(move |e: JsValue| {
|
||||||
web_sys::console::log_1(
|
web_sys::console::log_1(
|
||||||
|
@ -186,9 +187,9 @@ impl AppBridge {
|
||||||
.add_event_listener_with_callback("message", &cb.as_ref().unchecked_ref())
|
.add_event_listener_with_callback("message", &cb.as_ref().unchecked_ref())
|
||||||
.map_err(|e| AppBridgeError::JsValue(e))?;
|
.map_err(|e| AppBridgeError::JsValue(e))?;
|
||||||
Ok(cb)
|
Ok(cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dispatch_event(&mut self, action: Action) -> Result<(), AppBridgeError> {
|
pub fn dispatch_event(action: Action) -> Result<(), AppBridgeError> {
|
||||||
let window = web_sys::window().ok_or(AppBridgeError::WindowIsUndefined)?;
|
let window = web_sys::window().ok_or(AppBridgeError::WindowIsUndefined)?;
|
||||||
let parent = match window.parent() {
|
let parent = match window.parent() {
|
||||||
Ok(p) => p.ok_or(AppBridgeError::WindowParentIsUndefined)?,
|
Ok(p) => p.ok_or(AppBridgeError::WindowParentIsUndefined)?,
|
||||||
|
@ -201,12 +202,6 @@ impl AppBridge {
|
||||||
.post_message(&message, "*")
|
.post_message(&message, "*")
|
||||||
.map_err(|e| AppBridgeError::JsValue(e))?;
|
.map_err(|e| AppBridgeError::JsValue(e))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
|
||||||
|
|
||||||
pub fn notify_ready(&mut self) -> Result<&mut Self, AppBridgeError> {
|
|
||||||
self.dispatch_event(Action::NotifyReady("{}".to_owned()))?;
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
|
|
@ -3,14 +3,15 @@ pub mod apl;
|
||||||
pub mod bridge;
|
pub mod bridge;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod headers;
|
pub mod headers;
|
||||||
pub mod locales;
|
|
||||||
pub mod manifest;
|
pub mod manifest;
|
||||||
#[cfg(feature = "middleware")]
|
#[cfg(feature = "middleware")]
|
||||||
pub mod middleware;
|
pub mod middleware;
|
||||||
|
#[cfg(feature = "settings_manager")]
|
||||||
|
pub mod settings_manager;
|
||||||
pub mod webhooks;
|
pub mod webhooks;
|
||||||
|
|
||||||
use anyhow::bail;
|
#[cfg(feature = "redis_apl")]
|
||||||
|
use apl::redis_apl::RedisAplError;
|
||||||
use apl::{AplType, APL};
|
use apl::{AplType, APL};
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -50,40 +51,50 @@ impl std::fmt::Display for AuthData {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SaleorApp {
|
pub struct SaleorApp<E> {
|
||||||
pub apl: Box<dyn APL>,
|
pub apl: Box<dyn APL<E>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SaleorApp {
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub fn new(config: &Config) -> anyhow::Result<SaleorApp> {
|
pub enum CreateSaleorAppError {
|
||||||
|
#[error("Feature needed to use this APL is not enabled in cargo.toml")]
|
||||||
|
MissingFeature(String),
|
||||||
|
#[cfg(feature = "redis_apl")]
|
||||||
|
#[error("failed creating redis_apl, {0}")]
|
||||||
|
#[cfg(feature = "redis_apl")]
|
||||||
|
RedisAplError(#[from] RedisAplError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: std::error::Error> SaleorApp<E> {
|
||||||
|
pub fn new(config: &Config) -> Result<SaleorApp<E>, CreateSaleorAppError> {
|
||||||
use AplType::{File, Redis};
|
use AplType::{File, Redis};
|
||||||
fn decide_apl(config: &Config) -> anyhow::Result<Box<dyn APL>> {
|
fn decide_apl<E>(config: &Config) -> Box<dyn APL<E>> {
|
||||||
match config.apl {
|
match config.apl {
|
||||||
Redis => {
|
Redis => {
|
||||||
#[cfg(feature = "redis_apl")]
|
#[cfg(feature = "redis_apl")]
|
||||||
return Ok(Box::new(RedisApl::new(
|
return Box::new(
|
||||||
&config.apl_url,
|
RedisApl::new(&config.apl_url, &config.app_api_base_url)
|
||||||
&config.app_api_base_url,
|
.expect("failed creating redisapl"),
|
||||||
)?));
|
);
|
||||||
|
|
||||||
#[cfg(not(feature = "redis_apl"))]
|
#[cfg(not(feature = "redis_apl"))]
|
||||||
{
|
{
|
||||||
bail!("Tried starting app with apl that wasn't present at compile time (cargo feature missing)")
|
return CreateSaleorAppError ::MissingFeature("Tried starting app with redis apl that wasn't present at compile time (cargo feature missing)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File => {
|
File => {
|
||||||
#[cfg(feature = "file_apl")]
|
#[cfg(feature = "file_apl")]
|
||||||
return Ok(Box::new(FileApl {
|
return Box::new(FileApl {
|
||||||
path: config.apl_url.to_owned(),
|
path: config.apl_url.to_owned(),
|
||||||
}));
|
});
|
||||||
#[cfg(not(feature = "file_apl"))]
|
#[cfg(not(feature = "file_apl"))]
|
||||||
{
|
{
|
||||||
bail!("Tried starting app with apl that wasn't present at compile time (cargo feature missing)")
|
return CreateSaleorAppError ::MissingFeature("Tried starting app with file apl that wasn't present at compile time (cargo feature missing)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let apl = decide_apl(config)?;
|
let apl = decide_apl(config);
|
||||||
Ok(SaleorApp { apl })
|
Ok(SaleorApp { apl })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use strum_macros::EnumString;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, EnumString)]
|
|
||||||
pub enum LocaleCode {
|
|
||||||
Ar,
|
|
||||||
Az,
|
|
||||||
Bg,
|
|
||||||
Bn,
|
|
||||||
Ca,
|
|
||||||
Cs,
|
|
||||||
Da,
|
|
||||||
De,
|
|
||||||
El,
|
|
||||||
En,
|
|
||||||
Es,
|
|
||||||
EsCO,
|
|
||||||
Et,
|
|
||||||
Fa,
|
|
||||||
Fr,
|
|
||||||
Hi,
|
|
||||||
Hu,
|
|
||||||
Hy,
|
|
||||||
Id,
|
|
||||||
Is,
|
|
||||||
It,
|
|
||||||
Ja,
|
|
||||||
Ko,
|
|
||||||
Mn,
|
|
||||||
Nb,
|
|
||||||
Nl,
|
|
||||||
Pl,
|
|
||||||
Pt,
|
|
||||||
PtBR,
|
|
||||||
Ro,
|
|
||||||
Ru,
|
|
||||||
Sk,
|
|
||||||
Sl,
|
|
||||||
Sq,
|
|
||||||
Sr,
|
|
||||||
Sv,
|
|
||||||
Th,
|
|
||||||
Tr,
|
|
||||||
Uk,
|
|
||||||
Vi,
|
|
||||||
ZhHans,
|
|
||||||
ZhHant,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for LocaleCode {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::En
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,6 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
pub mod extension;
|
pub mod extension;
|
||||||
|
use strum_macros::EnumString;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::{config::Config, webhooks::WebhookManifest};
|
use crate::{config::Config, webhooks::WebhookManifest};
|
||||||
|
@ -49,6 +50,59 @@ pub enum AppExtensionMount {
|
||||||
OrderOverviewCreate,
|
OrderOverviewCreate,
|
||||||
OrderOverviewMoreActions,
|
OrderOverviewMoreActions,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, EnumString)]
|
||||||
|
#[strum(serialize_all = "lowercase")]
|
||||||
|
pub enum LocaleCode {
|
||||||
|
Ar,
|
||||||
|
Az,
|
||||||
|
Bg,
|
||||||
|
Bn,
|
||||||
|
Ca,
|
||||||
|
Cs,
|
||||||
|
Da,
|
||||||
|
De,
|
||||||
|
El,
|
||||||
|
En,
|
||||||
|
Es,
|
||||||
|
EsCO,
|
||||||
|
Et,
|
||||||
|
Fa,
|
||||||
|
Fr,
|
||||||
|
Hi,
|
||||||
|
Hu,
|
||||||
|
Hy,
|
||||||
|
Id,
|
||||||
|
Is,
|
||||||
|
It,
|
||||||
|
Ja,
|
||||||
|
Ko,
|
||||||
|
Mn,
|
||||||
|
Nb,
|
||||||
|
Nl,
|
||||||
|
Pl,
|
||||||
|
Pt,
|
||||||
|
PtBR,
|
||||||
|
Ro,
|
||||||
|
Ru,
|
||||||
|
Sk,
|
||||||
|
Sl,
|
||||||
|
Sq,
|
||||||
|
Sr,
|
||||||
|
Sv,
|
||||||
|
Th,
|
||||||
|
Tr,
|
||||||
|
Uk,
|
||||||
|
Vi,
|
||||||
|
ZhHans,
|
||||||
|
ZhHant,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for LocaleCode {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::En
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Default for AppExtensionMount {
|
impl Default for AppExtensionMount {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::ProductOverviewMoreActions
|
Self::ProductOverviewMoreActions
|
||||||
|
|
1
sdk/src/settings_manager/encrypted_metadata.rs
Normal file
1
sdk/src/settings_manager/encrypted_metadata.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
//TODO: How does cryptography in rust work TT
|
217
sdk/src/settings_manager/metadata.rs
Normal file
217
sdk/src/settings_manager/metadata.rs
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
use crate::AuthData;
|
||||||
|
|
||||||
|
use super::queries::{
|
||||||
|
DeleteAppMetadata, DeleteAppMetadataVariables, GetAppMetadata, GetAppMetadataVariables,
|
||||||
|
MetadataInput, SetAppMetadata, SetAppMetadataVariables,
|
||||||
|
};
|
||||||
|
use super::SettingsManager;
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use cynic::{http::SurfExt, QueryBuilder};
|
||||||
|
use cynic::{GraphQlError, MutationBuilder};
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
|
use serde::Serialize;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::hash::Hash;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Metadata<K: Hash + Eq + FromStr + ToString, V: Serialize + DeserializeOwned>(
|
||||||
|
pub HashMap<K, V>,
|
||||||
|
);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct MetadataSettingsManager<
|
||||||
|
K: Hash + Eq + FromStr + ToString,
|
||||||
|
V: Serialize + DeserializeOwned,
|
||||||
|
> {
|
||||||
|
pub metadata: Metadata<K, V>,
|
||||||
|
pub auth_data: AuthData,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum MetadataSettingsManagerError {
|
||||||
|
#[error("Error during graphql querys http request, {0}")]
|
||||||
|
HttpRequestError(surf::Error),
|
||||||
|
#[error("Graphql query contains errors, {0}")]
|
||||||
|
GraphQlError(#[from] GraphQlError),
|
||||||
|
#[error("Key was not found in hashmap/metadata")]
|
||||||
|
KeyNotFound,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<
|
||||||
|
K: Hash + Eq + Send + Sync + FromStr + ToString,
|
||||||
|
V: Send + Sync + Clone + Serialize + DeserializeOwned,
|
||||||
|
> SettingsManager<K, V, MetadataSettingsManagerError> for MetadataSettingsManager<K, V>
|
||||||
|
{
|
||||||
|
async fn get(&mut self, key: K, domain: &str) -> Result<V, MetadataSettingsManagerError> {
|
||||||
|
//TODO: Create a cache instead of refetching every time
|
||||||
|
self.remote_get(Some(domain)).await?;
|
||||||
|
let val = self
|
||||||
|
.metadata
|
||||||
|
.0
|
||||||
|
.get(&key)
|
||||||
|
.ok_or(MetadataSettingsManagerError::KeyNotFound)?;
|
||||||
|
Ok(val.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set(
|
||||||
|
&mut self,
|
||||||
|
key: K,
|
||||||
|
value: V,
|
||||||
|
domain: &str,
|
||||||
|
) -> Result<(), MetadataSettingsManagerError> {
|
||||||
|
let _ = self.metadata.0.insert(key, value);
|
||||||
|
self.remote_set(Some(domain)).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn delete(&mut self, key: K, domain: &str) -> Result<V, MetadataSettingsManagerError> {
|
||||||
|
let removed = self
|
||||||
|
.metadata
|
||||||
|
.0
|
||||||
|
.remove(&key)
|
||||||
|
.ok_or(MetadataSettingsManagerError::KeyNotFound)?;
|
||||||
|
self.remote_delete(Some(domain), vec![key]).await?;
|
||||||
|
Ok(removed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<
|
||||||
|
K: Hash + Eq + Send + Sync + FromStr + ToString,
|
||||||
|
V: Send + Sync + DeserializeOwned + Serialize,
|
||||||
|
> MetadataSettingsManager<K, V>
|
||||||
|
{
|
||||||
|
pub fn to_metadata_vec(&self) -> Vec<MetadataInput> {
|
||||||
|
self.metadata
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| MetadataInput {
|
||||||
|
key: k.to_string(),
|
||||||
|
value: serde_json::to_string(v)
|
||||||
|
.expect("failed parsing metadatainput to json string"),
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn remote_delete(
|
||||||
|
&mut self,
|
||||||
|
api_url: Option<&str>,
|
||||||
|
keys: Vec<K>,
|
||||||
|
) -> Result<(), MetadataSettingsManagerError> {
|
||||||
|
let app_id = cynic::Id::new(&self.auth_data.app_id);
|
||||||
|
let keys = keys.into_iter().map(|k| k.to_string()).collect::<Vec<_>>();
|
||||||
|
let operation = DeleteAppMetadata::build(DeleteAppMetadataVariables {
|
||||||
|
app_id: &app_id,
|
||||||
|
keys: keys.iter().map(|k| k.as_str()).collect(),
|
||||||
|
});
|
||||||
|
match surf::post(api_url.unwrap_or(&self.auth_data.saleor_api_url))
|
||||||
|
.header("authorization-bearer", &self.auth_data.token)
|
||||||
|
.run_graphql(operation)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(response) => {
|
||||||
|
if let Some(res_errors) = response.errors {
|
||||||
|
if let Some(e) = res_errors.get(0).cloned() {
|
||||||
|
return Err(e.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
debug!("{:?}", e);
|
||||||
|
return Err(MetadataSettingsManagerError::HttpRequestError(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
sets metadata (not the private ones) in saleor app
|
||||||
|
*/
|
||||||
|
pub async fn remote_set(
|
||||||
|
&mut self,
|
||||||
|
api_url: Option<&str>,
|
||||||
|
) -> Result<(), MetadataSettingsManagerError> {
|
||||||
|
let app_id = cynic::Id::new(&self.auth_data.app_id);
|
||||||
|
let operation = SetAppMetadata::build(SetAppMetadataVariables {
|
||||||
|
app_id: &app_id,
|
||||||
|
input: self.to_metadata_vec(),
|
||||||
|
});
|
||||||
|
match surf::post(api_url.unwrap_or(&self.auth_data.saleor_api_url))
|
||||||
|
.header("authorization-bearer", &self.auth_data.token)
|
||||||
|
.run_graphql(operation)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(response) => {
|
||||||
|
if let Some(res_errors) = response.errors {
|
||||||
|
if let Some(e) = res_errors.get(0).cloned() {
|
||||||
|
return Err(e.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
debug!("{:?}", e);
|
||||||
|
return Err(MetadataSettingsManagerError::HttpRequestError(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
refetches metadata from saleor (not the private ones) and parses them to a HashMap<K,V>
|
||||||
|
*/
|
||||||
|
pub async fn remote_get(
|
||||||
|
&mut self,
|
||||||
|
api_url: Option<&str>,
|
||||||
|
) -> Result<&mut Self, MetadataSettingsManagerError> {
|
||||||
|
let app_id = cynic::Id::new(&self.auth_data.app_id);
|
||||||
|
let operation = GetAppMetadata::build(GetAppMetadataVariables { app_id: &app_id });
|
||||||
|
match surf::post(api_url.unwrap_or(&self.auth_data.saleor_api_url))
|
||||||
|
.header("authorization-bearer", &self.auth_data.token)
|
||||||
|
.run_graphql(operation)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(response) => {
|
||||||
|
if let Some(res_errors) = response.errors {
|
||||||
|
if let Some(e) = res_errors.get(0).cloned() {
|
||||||
|
return Err(e.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(res) = response.data {
|
||||||
|
if let Some(app) = res.app {
|
||||||
|
let hashmap = app
|
||||||
|
.metadata
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|m| {
|
||||||
|
K::from_str(&m.key)
|
||||||
|
.ok()
|
||||||
|
.zip(serde_json::from_str(&m.value).ok())
|
||||||
|
})
|
||||||
|
.collect::<HashMap<K, V>>();
|
||||||
|
self.metadata = Metadata(hashmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.metadata = Metadata(HashMap::new());
|
||||||
|
return Ok(self);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
debug!("{:?}", e);
|
||||||
|
return Err(MetadataSettingsManagerError::HttpRequestError(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
creates a new manager, and also prefetches metadata from saleor (not the private ones) and parses them to a HashMap<K,V>
|
||||||
|
Make sure your types convert correctly into these types through FromStr, if either key or value is not converted correctly, both get dropped silently!
|
||||||
|
*/
|
||||||
|
pub async fn new(auth_data: AuthData) -> Result<Self, MetadataSettingsManagerError> {
|
||||||
|
let mut mngr = Self {
|
||||||
|
auth_data,
|
||||||
|
metadata: Metadata(HashMap::new()),
|
||||||
|
};
|
||||||
|
mngr.remote_get(None).await?;
|
||||||
|
Ok(mngr)
|
||||||
|
}
|
||||||
|
}
|
12
sdk/src/settings_manager/mod.rs
Normal file
12
sdk/src/settings_manager/mod.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
pub mod encrypted_metadata;
|
||||||
|
pub mod metadata;
|
||||||
|
pub mod queries;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
pub trait SettingsManager<K, V, E>: Send + Sync {
|
||||||
|
async fn get(&mut self, key: K, domain: &str) -> Result<V, E>;
|
||||||
|
async fn set(&mut self, key: K, value: V, domain: &str) -> Result<(), E>;
|
||||||
|
async fn delete(&mut self, key: K, domain: &str) -> Result<V, E>;
|
||||||
|
}
|
202
sdk/src/settings_manager/queries.rs
Normal file
202
sdk/src/settings_manager/queries.rs
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
#[cynic::schema("saleor")]
|
||||||
|
mod schema {}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryVariables, Debug)]
|
||||||
|
pub struct DeleteAppMetadataVariables<'a> {
|
||||||
|
pub app_id: &'a cynic::Id,
|
||||||
|
pub keys: Vec<&'a str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryVariables, Debug)]
|
||||||
|
pub struct SetAppPrivateMetadataVariables<'a> {
|
||||||
|
pub app_id: &'a cynic::Id,
|
||||||
|
pub input: Vec<MetadataInput>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryVariables, Debug)]
|
||||||
|
pub struct GetAppMetadataVariables<'a> {
|
||||||
|
pub app_id: &'a cynic::Id,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryVariables, Debug)]
|
||||||
|
pub struct GetAppPrivateMetadataVariables<'a> {
|
||||||
|
pub app_id: &'a cynic::Id,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryVariables, Debug)]
|
||||||
|
pub struct SetAppMetadataVariables<'a> {
|
||||||
|
pub app_id: &'a cynic::Id,
|
||||||
|
pub input: Vec<MetadataInput>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryVariables, Debug)]
|
||||||
|
pub struct DeleteAppPrivateMetadataVariables<'a> {
|
||||||
|
pub app_id: &'a cynic::Id,
|
||||||
|
pub keys: Vec<&'a str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
#[cynic(graphql_type = "Query", variables = "GetAppPrivateMetadataVariables")]
|
||||||
|
pub struct GetAppPrivateMetadata {
|
||||||
|
#[arguments(id: $app_id)]
|
||||||
|
pub app: Option<App>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
#[cynic(graphql_type = "Query", variables = "GetAppMetadataVariables")]
|
||||||
|
pub struct GetAppMetadata {
|
||||||
|
#[arguments(id: $app_id)]
|
||||||
|
pub app: Option<App2>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
#[cynic(
|
||||||
|
graphql_type = "Mutation",
|
||||||
|
variables = "SetAppPrivateMetadataVariables"
|
||||||
|
)]
|
||||||
|
pub struct SetAppPrivateMetadata {
|
||||||
|
#[arguments(id: $app_id, input: $input)]
|
||||||
|
pub update_private_metadata: Option<UpdatePrivateMetadata>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
pub struct UpdatePrivateMetadata {
|
||||||
|
pub item: Option<ObjectWithMetadata>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
#[cynic(graphql_type = "Mutation", variables = "SetAppMetadataVariables")]
|
||||||
|
pub struct SetAppMetadata {
|
||||||
|
#[arguments(id: $app_id, input: $input)]
|
||||||
|
pub update_metadata: Option<UpdateMetadata>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
pub struct UpdateMetadata {
|
||||||
|
pub item: Option<ObjectWithMetadata2>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
#[cynic(graphql_type = "ObjectWithMetadata")]
|
||||||
|
pub struct ObjectWithMetadata2 {
|
||||||
|
pub metadata: Vec<MetadataItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
#[cynic(
|
||||||
|
graphql_type = "Mutation",
|
||||||
|
variables = "DeleteAppPrivateMetadataVariables"
|
||||||
|
)]
|
||||||
|
pub struct DeleteAppPrivateMetadata {
|
||||||
|
#[arguments(id: $app_id, keys: $keys)]
|
||||||
|
pub delete_private_metadata: Option<DeletePrivateMetadata>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
#[cynic(graphql_type = "Mutation", variables = "DeleteAppMetadataVariables")]
|
||||||
|
pub struct DeleteAppMetadata {
|
||||||
|
#[arguments(id: $app_id, keys: $keys)]
|
||||||
|
pub delete_metadata: Option<DeleteMetadata>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
pub struct DeletePrivateMetadata {
|
||||||
|
pub item: Option<ObjectWithMetadata>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
pub struct DeleteMetadata {
|
||||||
|
pub item: Option<ObjectWithMetadata>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
pub struct ObjectWithMetadata {
|
||||||
|
pub private_metadata: Vec<MetadataItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
pub struct App {
|
||||||
|
pub private_metadata: Vec<MetadataItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
#[cynic(graphql_type = "App")]
|
||||||
|
pub struct App2 {
|
||||||
|
pub metadata: Vec<MetadataItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::QueryFragment, Debug)]
|
||||||
|
pub struct MetadataItem {
|
||||||
|
pub key: String,
|
||||||
|
pub value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(cynic::InputObject, Debug)]
|
||||||
|
pub struct MetadataInput {
|
||||||
|
pub key: String,
|
||||||
|
pub value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
query GetAppMetadata($app_id: ID!) {
|
||||||
|
app(id: $app_id) {
|
||||||
|
metadata {
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query GetAppPrivateMetadata($app_id: ID!) {
|
||||||
|
app(id: $app_id) {
|
||||||
|
privateMetadata {
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation SetAppMetadata($app_id: ID!, $input: [MetadataInput!]!) {
|
||||||
|
updateMetadata(id: $app_id, input: $input) {
|
||||||
|
item {
|
||||||
|
metadata {
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation SetAppPrivateMetadata($app_id: ID!, $input: [MetadataInput!]!) {
|
||||||
|
updatePrivateMetadata(id: $app_id, input: $input) {
|
||||||
|
item {
|
||||||
|
privateMetadata {
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation DeleteAppMetadata($app_id: ID!, $keys: [String!]!) {
|
||||||
|
deleteMetadata(id: $app_id, keys: $keys) {
|
||||||
|
item {
|
||||||
|
privateMetadata {
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation DeleteAppPrivateMetadata($app_id: ID!, $keys: [String!]!) {
|
||||||
|
deletePrivateMetadata(id: $app_id, keys: $keys) {
|
||||||
|
item {
|
||||||
|
privateMetadata {
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::headers::SALEOR_EVENT_HEADER;
|
use crate::headers::SALEOR_EVENT_HEADER;
|
||||||
use http::HeaderMap;
|
use http::{header::ToStrError, HeaderMap};
|
||||||
|
|
||||||
use super::{AsyncWebhookEventType, SyncWebhookEventType};
|
use super::{AsyncWebhookEventType, SyncWebhookEventType};
|
||||||
|
|
||||||
|
@ -9,20 +9,28 @@ pub enum EitherWebhookType {
|
||||||
Async(AsyncWebhookEventType),
|
Async(AsyncWebhookEventType),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum GetWebhookTypeError {
|
||||||
|
#[error("Failed parsing webhook type, {0}")]
|
||||||
|
ParseError(#[from] strum::ParseError),
|
||||||
|
#[error("Failed parsing header to str, {0}")]
|
||||||
|
ToStrError(#[from] ToStrError),
|
||||||
|
#[error("Missing Event type header")]
|
||||||
|
MissingWebhookTypeHeader,
|
||||||
|
}
|
||||||
//header "saleor-event" can have either sync or async type, so we return enum witch has either or
|
//header "saleor-event" can have either sync or async type, so we return enum witch has either or
|
||||||
pub fn get_webhook_event_type(header: &HeaderMap) -> anyhow::Result<EitherWebhookType> {
|
pub fn get_webhook_event_type(
|
||||||
|
header: &HeaderMap,
|
||||||
|
) -> Result<EitherWebhookType, GetWebhookTypeError> {
|
||||||
if let Some(event) = header.get(SALEOR_EVENT_HEADER) {
|
if let Some(event) = header.get(SALEOR_EVENT_HEADER) {
|
||||||
let event = event.to_str()?;
|
let event = event.to_str()?;
|
||||||
let s_event: Result<SyncWebhookEventType, _> = SyncWebhookEventType::try_from(event);
|
let s_event: Result<SyncWebhookEventType, _> = SyncWebhookEventType::try_from(event);
|
||||||
let a_event: Result<AsyncWebhookEventType, _> = AsyncWebhookEventType::try_from(event);
|
let a_event: Result<AsyncWebhookEventType, _> = AsyncWebhookEventType::try_from(event);
|
||||||
let event = match s_event {
|
let event = match s_event {
|
||||||
Ok(s) => EitherWebhookType::Sync(s),
|
Ok(s) => EitherWebhookType::Sync(s),
|
||||||
Err(_) => match a_event {
|
Err(_) => EitherWebhookType::Async(a_event?),
|
||||||
Ok(a) => EitherWebhookType::Async(a),
|
|
||||||
Err(e) => anyhow::bail!(e),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
return Ok(event);
|
return Ok(event);
|
||||||
}
|
}
|
||||||
anyhow::bail!("Missing event type header")
|
Err(GetWebhookTypeError::MissingWebhookTypeHeader)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue