Remove Anyhow completely, slight refactoring

This commit is contained in:
djkato 2024-11-15 01:37:52 +01:00
parent 27c039278c
commit 242fd2510f
12 changed files with 36433 additions and 124 deletions

70
Cargo.lock generated
View file

@ -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",

View file

@ -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"]

View file

@ -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
View 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

File diff suppressed because it is too large Load diff

View file

@ -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(())
} }
} }

View file

@ -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>;
} }

View file

@ -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 {

View file

@ -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 })
} }
} }

View file

@ -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
}
}

View file

@ -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

View file

@ -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)
} }