Skip to content

Commit

Permalink
web: expose product metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
sre committed Nov 18, 2023
1 parent 3f6a7b7 commit 39af083
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 2 deletions.
70 changes: 68 additions & 2 deletions src/bin/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,35 @@ pub struct RestockEntryLegacy {
best_before_date: i64,
}

#[derive(Type, Deserialize, Serialize)]
pub struct ProductMetadata {
product_size: u32,
product_size_is_weight: bool,
container_size: u32,
calories: u32,
carbohydrates: u32,
fats: u32,
proteins: u32,
deposit: u32,
container_deposit: u32,
}

impl Default for ProductMetadata {
fn default() -> Self {
Self {
product_size: 0,
product_size_is_weight: true,
container_size: 0,
calories: 0,
carbohydrates: 0,
fats: 0,
proteins: 0,
deposit: 0,
container_deposit: 0,
}
}
}

#[derive(Type, Deserialize, Serialize)]
pub struct RestockEntry {
timestamp: i64,
Expand Down Expand Up @@ -436,6 +465,8 @@ trait ShopDB {
async fn get_product_category(&self, ean: u64) -> zbus::Result<String>;
async fn get_product_deprecated(&self, ean: u64) -> zbus::Result<bool>;
async fn product_deprecate(&self, ean: u64, deprecated: bool) -> zbus::Result<()>;
async fn product_metadata_get(&self, ean: u64) -> zbus::Result<ProductMetadata>;
async fn product_metadata_set(&self, ean: u64, metadata: ProductMetadata) -> zbus::Result<()>;
async fn get_restocks(&self, ean: u64, descending: bool) -> zbus::Result<Vec<RestockEntryLegacy>>;
async fn bestbeforelist(&self) -> zbus::Result<Vec<BestBeforeEntry>>;
async fn get_supplier_list(&self) -> zbus::Result<Vec<Supplier>>;
Expand Down Expand Up @@ -593,6 +624,18 @@ async fn product_deprecate(ean: u64, deprecated: bool) -> zbus::Result<()> {
proxy.product_deprecate(ean, deprecated).await
}

async fn product_metadata_get(ean: u64) -> zbus::Result<ProductMetadata> {
let connection = Connection::system().await?;
let proxy = ShopDBProxy::new(&connection).await?;
proxy.product_metadata_get(ean).await
}

async fn product_metadata_set(ean: u64, metadata: ProductMetadata) -> zbus::Result<()> {
let connection = Connection::system().await?;
let proxy = ShopDBProxy::new(&connection).await?;
proxy.product_metadata_set(ean, metadata).await
}

async fn restock(user: i32, product: u64, amount: u32, price: u32, supplier: i32, best_before_date: i64) -> zbus::Result<()> {
let connection = Connection::system().await?;
let proxy = ShopDBProxy::new(&connection).await?;
Expand Down Expand Up @@ -1049,6 +1092,7 @@ async fn product_details(cookies: &CookieJar<'_>, ean: u64) -> Result<Template,
let deprecated = get_product_deprecated(ean).await?;
let prices = get_prices(ean).await?;
let legacyrestock = get_restocks(ean, false).await?;
let metadata = product_metadata_get(ean).await.ok().unwrap_or_default();

let mut restock = Vec::new();
for entry in legacyrestock {
Expand All @@ -1065,7 +1109,7 @@ async fn product_details(cookies: &CookieJar<'_>, ean: u64) -> Result<Template,

let suppliers = get_supplier_list().await?;

Ok(Template::render("products/details", context! { page: "products/details", session: session, ean: ean, aliases: aliases, name: name, category: category, amount: amount, deprecated: deprecated, prices: prices, restock: restock, suppliers: suppliers }))
Ok(Template::render("products/details", context! { page: "products/details", session: session, ean: ean, aliases: aliases, name: name, category: category, amount: amount, deprecated: deprecated, prices: prices, restock: restock, suppliers: suppliers, metadata: metadata }))
}

#[get("/products/<ean>/deprecate/<deprecated>")]
Expand Down Expand Up @@ -1187,6 +1231,28 @@ async fn web_product_alias_add(cookies: &CookieJar<'_>, ean: u64, alias: u64) ->
Ok(Json(alias))
}

#[post("/products/<ean>/metadata-set", format = "application/json", data = "<metadata>")]
async fn web_product_metadata_set(cookies: &CookieJar<'_>, ean: u64, metadata: Json<ProductMetadata>) -> Result<Json<()>, Forbidden<String>> {
let session = match get_session(cookies).await {
Err(error) => { return Err(Forbidden(error.to_string())); },
Ok(session) => session,
};

if !session.superuser && !session.auth_products {
return Err(Forbidden("Missing Permission".to_string()));
}

let metadata = metadata.into_inner();

match product_metadata_set(ean, metadata).await {
Err(error) => { return Err(Forbidden(error.to_string())); }, // TODO
Ok(_) => {},
};

Ok(Json(()))
}


#[get("/aliases")]
async fn aliases(cookies: &CookieJar<'_>) -> Result<Template, WebShopError> {
let session = get_session(cookies).await?;
Expand Down Expand Up @@ -1807,7 +1873,7 @@ fn rocket() -> _ {
rocket::custom(figment)
.register("/", catchers![not_found])
.mount("/static", rocket::fs::FileServer::from(staticpath))
.mount("/", routes![login, logout, index, products, product_new, product_details, product_details_json, web_product_deprecate, web_product_add_prices, web_product_restock, web_product_alias_add, product_bestbefore, product_inventory, product_inventory_apply, aliases, suppliers, web_suppliers_new, cashbox, cashbox_state, cashbox_history_json, cashbox_update, cashbox_details, users, user_info, user_sound_theme_set, user_password_set, user_toggle_auth, user_invoice, user_invoice_full, user_stats, user_import, user_import_upload, user_import_apply, user_import_pgp, user_import_pgp_upload])
.mount("/", routes![login, logout, index, products, product_new, product_details, product_details_json, web_product_deprecate, web_product_add_prices, web_product_restock, web_product_alias_add, web_product_metadata_set, product_bestbefore, product_inventory, product_inventory_apply, aliases, suppliers, web_suppliers_new, cashbox, cashbox_state, cashbox_history_json, cashbox_update, cashbox_details, users, user_info, user_sound_theme_set, user_password_set, user_toggle_auth, user_invoice, user_invoice_full, user_stats, user_import, user_import_upload, user_import_apply, user_import_pgp, user_import_pgp_upload])
.attach(Template::custom(|engines| {
engines.tera.register_filter("cent2euro", cent2euro);
engines.tera.register_filter("gendericon", gendericon);
Expand Down
48 changes: 48 additions & 0 deletions templates/products/details.html.tera
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,21 @@
{% endif %}
</div>
<div class="col">
<h2>Metadata</h2>
<form onsubmit="event.preventDefault(); submit_metadata();">
<table id="metadatatable" class="table table-bordered table-striped table-hover">
<tr><th>Product Size (e.g. 330ml, 100g)</th><td><div class="row"><div class="form-group col"><input id="product_size" name="product_size" placeholder="42" aria-label="product size" type="number" class="form-control" value="{{ metadata.product_size }}"></div><div class="form-group col-auto"><select class="form-control" id="product_size_is_weight" name="product_size_is_weight"><option value="1" {% if metadata.product_size_is_weight == true %}selected{% endif %}>g</option><option value="0" {% if metadata.product_size_is_weight == false %}selected{% endif %}>ml</option></select></div></div></td></tr>
<tr><th>Container Size (e.g. 20 bottles)</th><td><input id="container_size" name="container_size" aria-label="container size" type="number" class="form-control" value="{{ metadata.container_size }}"></td></tr>
<tr><th>Calories (kcal)<br>(for product size)</th><td><input id="calories" name="calories" aria-label="calories" type="number" class="form-control" value="{{ metadata.calories }}"></td></tr>
<tr><th>Carbohydrates (g)<br>(for product size)</th><td><input id="carbohydrates" name="carbohydrates" aria-label="carbohydrates" type="number" class="form-control" value="{{ metadata.carbohydrates }}"></td></tr>
<tr><th>Fats (g)<br>(for product size)</th><td><input id="fats" name="fats" aria-label="fats" type="number" class="form-control" value="{{ metadata.fats }}"></td></tr>
<tr><th>Proteins (g)<br>(for product size)</th><td><input id="proteins" name="proteins" aria-label="proteins" type="number" class="form-control" value="{{ metadata.proteins }}"></td></tr>
<tr><th>Deposit (€)</th><td><input id="deposit" name="deposit" aria-label="deposit" type="number" class="form-control" value="{{ metadata.deposit | cent2euro }}"></td></tr>
<tr><th>Container Deposit (€)</th><td><input id="container_deposit" name="container_deposit" aria-label="container_deposit" type="number" class="form-control" value="{{ metadata.container_deposit | cent2euro }}"></td></tr>
<tr><td></td><td><button id="updatemetadata" class="btn btn-primary" type="button" {% if not session.auth_products %}disabled{% endif %}>Update Metadata</button></td></tr>
</table>
</form>

<h2>Restock</h2>

<table id="restocktable" class="table table-bordered table-striped table-hover">
Expand Down Expand Up @@ -188,6 +203,38 @@
}
}

var submit_metadata = function() {
var product_size = parseInt($("#product_size").val());
var product_size_is_weight = parseInt($("#product_size_is_weight").val()) == 1;
var container_size = parseInt($("#container_size").val());
var calories = parseInt($("#calories").val());
var carbohydrates = parseInt($("#carbohydrates").val());
var fats = parseInt($("#fats").val());
var proteins = parseInt($("#proteins").val());
var deposit = euro2cent($("#deposit").val());
var container_deposit = euro2cent($("#container_deposit").val());

var requestdata = {
product_size: product_size,
product_size_is_weight: product_size_is_weight,
container_size: container_size,
calories: calories,
carbohydrates: carbohydrates,
fats: fats,
proteins: proteins,
deposit: deposit,
container_deposit: container_deposit,
};

console.log("request: " + requestdata)

var req = $.postJSON(
"/products/{{ ean }}/metadata-set",
requestdata,
function( data ) { }
);
}

{% if session.auth_products %}
$(function () {
$('#addalias').popover({
Expand All @@ -204,6 +251,7 @@
$('#addalias').on('click', function (e) { submit_add_alias(); });
$('#addprices').on('click', function (e) { submit_add_prices(); });
$('#restock').on('click', function (e) { submit_restock(); });
$('#updatemetadata').on('click', function (e) { submit_metadata(); });

$('#deprecatedbutton').on('click', function (e) {
var state = $('#deprecatedbutton').html() === "Active";
Expand Down

0 comments on commit 39af083

Please sign in to comment.