Improve tests
This commit is contained in:
parent
38bed6f835
commit
4097e92268
1
.env
1
.env
@ -1,3 +1,4 @@
|
||||
DATABASE_URL=postgres://postgres@localhost/bazzar
|
||||
PASS_SALT=18CHwV7eGFAea16z+qMKZg
|
||||
RUST_LOG=debug
|
||||
KEY_SECRET="NEPJs#8jjn8SK8GC7QEC^*P844UgsyEbQB8mRWXkT%3mPrwewZoc25MMby9H#R*w2KzaQgMkk#Pif$kxrLy*N5L!Ch%jxbWoa%gb"
|
||||
|
@ -17,9 +17,11 @@
|
||||
justify-content: space-between;
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
fieldset > label {
|
||||
width: 45%;
|
||||
}
|
||||
|
||||
fieldset > input, fieldset > textarea {
|
||||
width: 54%;
|
||||
}
|
||||
@ -31,7 +33,15 @@
|
||||
<body>
|
||||
<div style="display: flex;justify-content: space-between;">
|
||||
<div style="width: 49%">
|
||||
<form>
|
||||
<form style="width: 100%">
|
||||
<fieldset>
|
||||
<label for="op">Operation</label>
|
||||
<select name="op" id="op">
|
||||
<option value="auto-login">Auto login</option>
|
||||
<option value="get-products">Get products</option>
|
||||
<option value="create-product">Create product</option>
|
||||
</select>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<label for="method">Method</label>
|
||||
<select id="method">
|
||||
@ -51,7 +61,11 @@
|
||||
</form>
|
||||
</div>
|
||||
<div style="width: 49%">
|
||||
<pre style="background: black; width: 100%; min-height: 300px"><code id="output" class="language-json"></code></pre>
|
||||
<pre style="background: black; width: 100%; min-height: 300px"><code
|
||||
id="output"
|
||||
class="language-json"
|
||||
style="overflow: auto"
|
||||
></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
@ -62,6 +76,46 @@
|
||||
const urlEl = form.querySelector('#path');
|
||||
const paramsEl = form.querySelector('#params');
|
||||
const mthEl = form.querySelector('#method');
|
||||
const opEL = form.querySelector('#op');
|
||||
|
||||
const send = (method, path, params) => {
|
||||
const rest = method === 'GET'
|
||||
? {}
|
||||
: { body: JSON.stringify(params), headers: { 'Content-Type': 'application/json' } };
|
||||
path = method === 'GET'
|
||||
? `${ path }?${ JSON.stringify(params) }`
|
||||
: path;
|
||||
|
||||
fetch(`${ path }`, { ...rest, method })
|
||||
.then(async (res) => {
|
||||
if (res.status < 400) {
|
||||
const json = await res.json();
|
||||
out.innerHTML = Prism.highlight(JSON.stringify(json, null, 4), Prism.languages.json, 'json');
|
||||
} else {
|
||||
out.innerHTML = await res.text();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
opEL.addEventListener('change', () => {
|
||||
switch (opEL.value) {
|
||||
case 'auto-login':
|
||||
paramsEl.value = `login=Eraden\npassword=text`
|
||||
return send(mthEl.value = 'POST', urlEl.value = '/admin/sign-in', { login: 'Eraden', password: 'test' })
|
||||
case 'get-products':
|
||||
return send(mthEl.value = 'GET', urlEl.value = '/admin/api/v1/products', {})
|
||||
case 'create-product':
|
||||
const p = {
|
||||
name: 'Foo',
|
||||
short_description: 'asd',
|
||||
long_description: 'asjdoiajd ajio djaso idja s',
|
||||
price_major: 12,
|
||||
price_minor: 0,
|
||||
};
|
||||
paramsEl.value = Object.entries(p).map((k, v) => `${ k }=${ v }}`).join('\n');
|
||||
return send(mthEl.value = 'POST', urlEl.value = '/admin/api/v1/product', p)
|
||||
}
|
||||
})
|
||||
|
||||
form.addEventListener('submit', (ev) => {
|
||||
ev.preventDefault();
|
||||
@ -74,21 +128,15 @@
|
||||
paramsEl.value.split("\n").forEach(s => {
|
||||
if (!s.length) return;
|
||||
let [k, ...v] = s.split("=");
|
||||
params[k] = Array(v).join('=');
|
||||
v = Array(v).join('=')
|
||||
try {
|
||||
v = JSON.parse(v);
|
||||
} catch (_) {
|
||||
}
|
||||
params[k] = v;
|
||||
});
|
||||
|
||||
const rest = method === 'GET'
|
||||
? {}
|
||||
: { body: JSON.stringify(params), headers: { 'Content-Type': 'application/json' } };
|
||||
path = method === 'GET'
|
||||
? `${ path }?${ JSON.stringify(params) }`
|
||||
: path;
|
||||
|
||||
fetch(`${ path }`, { ...rest, method })
|
||||
.then(res => res.json())
|
||||
.then(json => {
|
||||
out.innerHTML = Prism.highlight(JSON.stringify(json), Prism.languages.json, 'json');
|
||||
})
|
||||
send(method, path, params)
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
@ -152,7 +152,11 @@ impl Config {
|
||||
}
|
||||
|
||||
async fn server(opts: ServerOpts) -> Result<()> {
|
||||
let secret_key = Key::generate();
|
||||
let secret_key = {
|
||||
let key_secret = std::env::var("KEY_SECRET")
|
||||
.expect("session requires secret key with 64 or more characters");
|
||||
Key::from(key_secret.as_bytes())
|
||||
};
|
||||
let redis_connection_string = "127.0.0.1:6379";
|
||||
|
||||
let config = Arc::new(Config::load());
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::fmt::Formatter;
|
||||
|
||||
use derive_more::{Deref, Display};
|
||||
use derive_more::{Deref, Display, From};
|
||||
use serde::de::{Error, Visitor};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
|
||||
@ -61,29 +61,21 @@ pub enum ShoppingCartState {
|
||||
Closed,
|
||||
}
|
||||
|
||||
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
|
||||
#[derive(sqlx::Type, Serialize, Deserialize, Deref, From)]
|
||||
#[sqlx(transparent)]
|
||||
#[serde(transparent)]
|
||||
pub struct PriceMajor(NonNegative);
|
||||
|
||||
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
|
||||
#[derive(sqlx::Type, Serialize, Deserialize, Deref, From)]
|
||||
#[sqlx(transparent)]
|
||||
#[serde(transparent)]
|
||||
pub struct PriceMinor(NonNegative);
|
||||
|
||||
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
|
||||
#[derive(sqlx::Type, Serialize, Deserialize, Deref, From)]
|
||||
#[sqlx(transparent)]
|
||||
#[serde(transparent)]
|
||||
pub struct Quantity(NonNegative);
|
||||
|
||||
impl TryFrom<NonNegative> for Quantity {
|
||||
type Error = TransformError;
|
||||
|
||||
fn try_from(value: NonNegative) -> Result<Self, Self::Error> {
|
||||
Ok(Self(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<i32> for Quantity {
|
||||
type Error = TransformError;
|
||||
|
||||
@ -112,7 +104,7 @@ impl<'de> serde::Deserialize<'de> for Email {
|
||||
type Value = String;
|
||||
|
||||
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("this is not valid e-mail address")
|
||||
formatter.write_str("valid e-mail address")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||
@ -158,7 +150,7 @@ impl<'de> serde::Deserialize<'de> for NonNegative {
|
||||
type Value = i32;
|
||||
|
||||
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("this is not valid e-mail address")
|
||||
formatter.write_str("value equal or greater than 0")
|
||||
}
|
||||
|
||||
fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
|
||||
|
@ -14,7 +14,7 @@ use actix_web::web::{Data, Json, ServiceConfig};
|
||||
use actix_web::{delete, get, patch, post, HttpResponse};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[get("products")]
|
||||
#[get("/products")]
|
||||
async fn products(session: Session, db: Data<Addr<Database>>) -> routes::Result<HttpResponse> {
|
||||
session.require_admin()?;
|
||||
|
||||
@ -32,7 +32,7 @@ pub struct UpdateProduct {
|
||||
pub price_minor: PriceMinor,
|
||||
}
|
||||
|
||||
#[patch("product")]
|
||||
#[patch("/product")]
|
||||
async fn update_product(
|
||||
session: Session,
|
||||
db: Data<Addr<Database>>,
|
||||
@ -56,7 +56,6 @@ async fn update_product(
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CreateProduct {
|
||||
pub id: ProductId,
|
||||
pub name: ProductName,
|
||||
pub short_description: ProductShortDesc,
|
||||
pub long_description: ProductLongDesc,
|
||||
@ -65,7 +64,7 @@ pub struct CreateProduct {
|
||||
pub price_minor: PriceMinor,
|
||||
}
|
||||
|
||||
#[post("product")]
|
||||
#[post("/product")]
|
||||
async fn create_product(
|
||||
session: Session,
|
||||
db: Data<Addr<Database>>,
|
||||
@ -91,7 +90,7 @@ pub struct DeleteProduct {
|
||||
pub id: ProductId,
|
||||
}
|
||||
|
||||
#[delete("product")]
|
||||
#[delete("/product")]
|
||||
async fn delete_product(
|
||||
session: Session,
|
||||
db: Data<Addr<Database>>,
|
||||
|
@ -11,7 +11,7 @@ use actix_web::web::{Data, Json, ServiceConfig};
|
||||
use actix_web::{delete, get, patch, post, HttpResponse};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[get("stocks")]
|
||||
#[get("/stocks")]
|
||||
async fn stocks(session: Session, db: Data<Addr<Database>>) -> routes::Result<HttpResponse> {
|
||||
session.require_admin()?;
|
||||
|
||||
@ -26,7 +26,7 @@ pub struct UpdateStock {
|
||||
pub quantity_unit: QuantityUnit,
|
||||
}
|
||||
|
||||
#[patch("stock")]
|
||||
#[patch("/stock")]
|
||||
async fn update_stock(
|
||||
session: Session,
|
||||
db: Data<Addr<Database>>,
|
||||
@ -47,13 +47,12 @@ async fn update_stock(
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CreateStock {
|
||||
pub id: StockId,
|
||||
pub product_id: ProductId,
|
||||
pub quantity: Quantity,
|
||||
pub quantity_unit: QuantityUnit,
|
||||
}
|
||||
|
||||
#[post("stock")]
|
||||
#[post("/stock")]
|
||||
async fn create_stock(
|
||||
session: Session,
|
||||
db: Data<Addr<Database>>,
|
||||
@ -76,7 +75,7 @@ pub struct DeleteStock {
|
||||
pub id: StockId,
|
||||
}
|
||||
|
||||
#[delete("stock")]
|
||||
#[delete("/stock")]
|
||||
async fn delete_stock(
|
||||
session: Session,
|
||||
db: Data<Addr<Database>>,
|
||||
|
Loading…
Reference in New Issue
Block a user