mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-27 16:24:07 +02:00
product editor
This commit is contained in:
parent
f36505a38e
commit
e494277978
@ -3,8 +3,107 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src="product_editor.js" type="module" defer></script>
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
max-width: 1600px;
|
||||
}
|
||||
#product-list {
|
||||
border-spacing: 0;
|
||||
border: 1px solid black;
|
||||
}
|
||||
#product-list th {
|
||||
text-align: left;
|
||||
padding: 5px 10px;
|
||||
background-color: #eee;
|
||||
border-right: 1px solid lightgray;
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
#product-list th:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
#product-list td {
|
||||
border-top: 1px solid black;
|
||||
border-right: 1px solid lightgray;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
#product-list td:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
#product-list tr:nth-child(2n) td {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
background-color: #F9F9F9;
|
||||
text-align: left;
|
||||
margin-top: 1rem;
|
||||
display: inline-block;
|
||||
}
|
||||
legend {
|
||||
font-weight: bold;
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
#editor table {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
#editor td {
|
||||
padding: 0.25rem;
|
||||
vertical-align: top;
|
||||
}
|
||||
textarea {
|
||||
font-family: inherit;
|
||||
resize: vertical;
|
||||
}
|
||||
#editor input, #editor textarea {
|
||||
width: 250px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Product editor</h1>
|
||||
<h2>Products</h2>
|
||||
<table id="product-list">
|
||||
</table>
|
||||
<fieldset>
|
||||
<legend>Editor</legend>
|
||||
|
||||
<form id="editor">
|
||||
<center>
|
||||
<button id="load">Load</button>
|
||||
<button id="save">Save</button>
|
||||
<button id="new">New</button>
|
||||
</center>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><label for="product-id">id: </label></td>
|
||||
<td>
|
||||
<input id="product-id" type="text">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="product-name">name: </label></td>
|
||||
<td><input id="product-name" type="text"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="product-price">price (dkk): </label></td>
|
||||
<td><input id="product-price" type="number" step="0.01"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="product-description">description: </label></td>
|
||||
<td><textarea id="product-description"></textarea></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="product-coord">coord_id: </label></td>
|
||||
<td><input id="product-coord" type="text"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="product-barcode">barcode: </label></td>
|
||||
<td><input id="product-barcode" type="text"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</fieldset>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,3 +1,135 @@
|
||||
|
||||
console.log("hello world")
|
||||
const productList = document.querySelector("#product-list");
|
||||
const editor = {
|
||||
form: document.querySelector("#editor"),
|
||||
loadButton: document.querySelector("#editor #load"),
|
||||
saveButton: document.querySelector("#editor #save"),
|
||||
newButton: document.querySelector("#editor #new"),
|
||||
idInput: document.querySelector("#editor #product-id"),
|
||||
nameInput: document.querySelector("#editor #product-name"),
|
||||
priceInput: document.querySelector("#editor #product-price"),
|
||||
descriptionTextarea: document.querySelector("#editor #product-description"),
|
||||
coordInput: document.querySelector("#editor #product-coord"),
|
||||
barcodeInput: document.querySelector("#editor #product-barcode"),
|
||||
};
|
||||
|
||||
let products = [];
|
||||
|
||||
let selectedProductId = null;
|
||||
|
||||
function selectProduct(product) {
|
||||
selectedProductId = product.id;
|
||||
|
||||
editor.idInput.value = product.id.toString();
|
||||
editor.nameInput.value = product.name;
|
||||
editor.priceInput.value = product.price_dkk_cent / 100;
|
||||
editor.descriptionTextarea.value = product.description;
|
||||
editor.coordInput.value = product.coord_id.toString();
|
||||
editor.barcodeInput.value = product.barcode.toString();
|
||||
}
|
||||
|
||||
async function loadProduct() {
|
||||
selectedProductId = parseInt(editor.idInput.value);
|
||||
|
||||
const product = products.find(product => product.id === selectedProductId);
|
||||
if (!product){
|
||||
alert(`no product with id ${selectedProductId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
selectProduct(product);
|
||||
}
|
||||
|
||||
function productFromForm() {
|
||||
return {
|
||||
id: parseInt(editor.idInput.value),
|
||||
name: editor.nameInput.value,
|
||||
description: editor.descriptionTextarea.value,
|
||||
price_dkk_cent: Math.floor(parseFloat(editor.priceInput.value) * 100),
|
||||
coord_id: parseInt(editor.coordInput.value),
|
||||
barcode: editor.barcodeInput.value,
|
||||
}
|
||||
}
|
||||
|
||||
async function saveProduct() {
|
||||
const product = productFromForm();
|
||||
await fetch("/api/products/update", {
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/json"},
|
||||
body: JSON.stringify(product),
|
||||
}).then(res => res.json());
|
||||
|
||||
await updateProductList();
|
||||
|
||||
}
|
||||
|
||||
async function newProduct() {
|
||||
const product = productFromForm();
|
||||
await fetch("/api/products/create", {
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/json"},
|
||||
body: JSON.stringify(product),
|
||||
}).then(res => res.json());
|
||||
|
||||
await updateProductList();
|
||||
}
|
||||
|
||||
async function updateProductList() {
|
||||
const res = await fetch("/api/products/all")
|
||||
.then(res => res.json());
|
||||
|
||||
products = res.products;
|
||||
|
||||
productList.innerHTML = `
|
||||
<tr>
|
||||
<th>id</th>
|
||||
<th>name</th>
|
||||
<th>price_dkk_cent</th>
|
||||
<th>description</th>
|
||||
<th>coord_id</th>
|
||||
<th>barcode</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
`;
|
||||
productList.innerHTML += products
|
||||
.map(product => `
|
||||
<tr>
|
||||
<td><code>${product.id}</code></td>
|
||||
<td><strong>${product.name}</strong></td>
|
||||
<td>${product.price_dkk_cent / 100} dkk</td>
|
||||
<td>${product.description}</td>
|
||||
<td><code>${product.coord_id}</code></td>
|
||||
<td><code>${product.barcode}</code></td>
|
||||
<td><button id="product-${product.id}-edit">Edit</button></td>
|
||||
</tr>
|
||||
`)
|
||||
.join("");
|
||||
|
||||
for (const product of products) {
|
||||
document
|
||||
.querySelector(`#product-${product.id}-edit`)
|
||||
.addEventListener("click", () => {
|
||||
selectProduct(product);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
updateProductList();
|
||||
|
||||
editor.form
|
||||
.addEventListener("submit", (e) => {
|
||||
e.preventDefault();
|
||||
});
|
||||
editor.loadButton
|
||||
.addEventListener("click", (e) => {
|
||||
loadProduct();
|
||||
});
|
||||
editor.saveButton
|
||||
.addEventListener("click", (e) => {
|
||||
saveProduct();
|
||||
});
|
||||
editor.newButton
|
||||
.addEventListener("click", (e) => {
|
||||
newProduct();
|
||||
});
|
||||
|
||||
|
@ -36,6 +36,9 @@ void route_post_set_number(HttpCtx* ctx);
|
||||
void route_get_not_found(HttpCtx* ctx);
|
||||
|
||||
void route_get_products_all(HttpCtx* ctx);
|
||||
void route_post_products_create(HttpCtx* ctx);
|
||||
void route_post_products_update(HttpCtx* ctx);
|
||||
|
||||
void route_get_product_editor_html(HttpCtx* ctx);
|
||||
void route_get_product_editor_js(HttpCtx* ctx);
|
||||
|
||||
|
@ -36,6 +36,83 @@ void route_get_products_all(HttpCtx* ctx)
|
||||
string_destroy(&res);
|
||||
}
|
||||
|
||||
void route_post_products_create(HttpCtx* ctx)
|
||||
{
|
||||
Cx* cx = http_ctx_user_ctx(ctx);
|
||||
|
||||
const char* body_str = http_ctx_req_body(ctx);
|
||||
JsonValue* body_json = json_parse(body_str, strlen(body_str));
|
||||
if (!body_json) {
|
||||
RESPOND_BAD_REQUEST(ctx, "bad request");
|
||||
return;
|
||||
}
|
||||
|
||||
ProductsCreateReq req;
|
||||
int parse_result = products_create_req_from_json(&req, body_json);
|
||||
json_free(body_json);
|
||||
if (parse_result != 0) {
|
||||
RESPOND_BAD_REQUEST(ctx, "bad request");
|
||||
return;
|
||||
}
|
||||
|
||||
Product product = {
|
||||
.id = 0,
|
||||
.name = str_dup(req.name),
|
||||
.price_dkk_cent = req.price_dkk_cent,
|
||||
.description = str_dup(req.description),
|
||||
.coord_id = req.coord_id,
|
||||
.barcode = str_dup(req.barcode),
|
||||
};
|
||||
products_create_req_destroy(&req);
|
||||
|
||||
DbRes db_res = db_product_insert(cx->db, &product);
|
||||
if (db_res != DbRes_Ok) {
|
||||
RESPOND_SERVER_ERROR(ctx);
|
||||
goto l0_return;
|
||||
}
|
||||
|
||||
RESPOND_JSON(ctx, 200, "{\"ok\":true}");
|
||||
|
||||
l0_return:
|
||||
product_destroy(&product);
|
||||
}
|
||||
|
||||
void route_post_products_update(HttpCtx* ctx)
|
||||
{
|
||||
Cx* cx = http_ctx_user_ctx(ctx);
|
||||
|
||||
const char* body_str = http_ctx_req_body(ctx);
|
||||
printf("body_str = '%s'\n", body_str);
|
||||
|
||||
JsonValue* body_json = json_parse(body_str, strlen(body_str));
|
||||
printf("body_json = %p\n", (void*)body_json);
|
||||
|
||||
if (!body_json) {
|
||||
RESPOND_BAD_REQUEST(ctx, "bad request");
|
||||
return;
|
||||
}
|
||||
|
||||
Product product;
|
||||
int parse_result = product_from_json(&product, body_json);
|
||||
printf("parse_result = %d\n", parse_result);
|
||||
json_free(body_json);
|
||||
if (parse_result != 0) {
|
||||
RESPOND_BAD_REQUEST(ctx, "bad request");
|
||||
return;
|
||||
}
|
||||
|
||||
DbRes db_res = db_product_update(cx->db, &product);
|
||||
if (db_res != DbRes_Ok) {
|
||||
RESPOND_SERVER_ERROR(ctx);
|
||||
goto l0_return;
|
||||
}
|
||||
|
||||
RESPOND_JSON(ctx, 200, "{\"ok\":true}");
|
||||
|
||||
l0_return:
|
||||
product_destroy(&product);
|
||||
}
|
||||
|
||||
static inline int read_and_send_file(HttpCtx* ctx,
|
||||
const char* filepath,
|
||||
size_t max_file_size,
|
||||
|
@ -30,6 +30,12 @@ DbRes db_user_with_email_exists(Db* db, bool* exists, const char* email);
|
||||
/// `user` is an out parameter.
|
||||
DbRes db_user_with_email(Db* db, User* user, const char* email);
|
||||
|
||||
/// `product.id` are ignored.
|
||||
DbRes db_product_insert(Db* db, const Product* product);
|
||||
|
||||
/// Uses `user.id` to find model.
|
||||
DbRes db_product_update(Db* db, const Product* product);
|
||||
|
||||
/// `product` is an out parameter.
|
||||
DbRes db_product_with_id(Db* db, Product* product, int64_t id);
|
||||
|
||||
|
@ -285,7 +285,97 @@ l0_return:
|
||||
return res;
|
||||
}
|
||||
|
||||
/// `product` is an out parameter.
|
||||
DbRes db_product_insert(Db* db, const Product* product)
|
||||
{
|
||||
static_assert(sizeof(Product) == 48, "model has changed");
|
||||
|
||||
sqlite3* connection;
|
||||
CONNECT;
|
||||
DbRes res;
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
int prepare_res = sqlite3_prepare_v2(connection,
|
||||
"INSERT INTO products"
|
||||
" (name, price_dkk_cent, description, coord, barcode)"
|
||||
" VALUES (?, ?, ?, ?, ?)",
|
||||
-1,
|
||||
&stmt,
|
||||
NULL);
|
||||
if (prepare_res != SQLITE_OK) {
|
||||
REPORT_SQLITE3_ERROR();
|
||||
res = DbRes_Error;
|
||||
goto l0_return;
|
||||
}
|
||||
|
||||
sqlite3_bind_text(stmt, 1, product->name, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_int64(stmt, 2, product->price_dkk_cent);
|
||||
sqlite3_bind_text(stmt, 3, product->description, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_int64(stmt, 4, product->coord_id);
|
||||
sqlite3_bind_text(stmt, 5, product->barcode, -1, SQLITE_STATIC);
|
||||
|
||||
int step_res = sqlite3_step(stmt);
|
||||
if (step_res != SQLITE_DONE) {
|
||||
REPORT_SQLITE3_ERROR();
|
||||
res = DbRes_Error;
|
||||
goto l0_return;
|
||||
}
|
||||
|
||||
res = DbRes_Ok;
|
||||
l0_return:
|
||||
if (stmt)
|
||||
sqlite3_finalize(stmt);
|
||||
DISCONNECT;
|
||||
return res;
|
||||
}
|
||||
|
||||
DbRes db_product_update(Db* db, const Product* product)
|
||||
{
|
||||
static_assert(sizeof(Product) == 48, "model has changed");
|
||||
|
||||
sqlite3* connection;
|
||||
CONNECT;
|
||||
DbRes res;
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
int prepare_res = sqlite3_prepare_v2(connection,
|
||||
"UPDATE products SET"
|
||||
" name = ?,"
|
||||
" price_dkk_cent = ?,"
|
||||
" description = ?,"
|
||||
" coord = ?,"
|
||||
" barcode = ?"
|
||||
" WHERE id = ?",
|
||||
-1,
|
||||
&stmt,
|
||||
NULL);
|
||||
if (prepare_res != SQLITE_OK) {
|
||||
REPORT_SQLITE3_ERROR();
|
||||
res = DbRes_Error;
|
||||
goto l0_return;
|
||||
}
|
||||
|
||||
sqlite3_bind_text(stmt, 1, product->name, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_int64(stmt, 2, product->price_dkk_cent);
|
||||
sqlite3_bind_text(stmt, 3, product->description, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_int64(stmt, 4, product->coord_id);
|
||||
sqlite3_bind_text(stmt, 5, product->barcode, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_int64(stmt, 6, product->id);
|
||||
|
||||
int step_res = sqlite3_step(stmt);
|
||||
if (step_res != SQLITE_DONE) {
|
||||
fprintf(stderr, "error: %s\n", sqlite3_errmsg(connection));
|
||||
res = DbRes_Error;
|
||||
goto l0_return;
|
||||
}
|
||||
|
||||
res = DbRes_Ok;
|
||||
l0_return:
|
||||
if (stmt)
|
||||
sqlite3_finalize(stmt);
|
||||
DISCONNECT;
|
||||
return res;
|
||||
}
|
||||
|
||||
DbRes db_product_with_id(Db* db, Product* product, int64_t id)
|
||||
{
|
||||
static_assert(sizeof(Product) == 48, "model has changed");
|
||||
|
@ -148,6 +148,23 @@ void json_parser_destroy(JsonParser* p)
|
||||
(void)p;
|
||||
}
|
||||
|
||||
static inline void free_unused_arr(Arr* arr)
|
||||
{
|
||||
for (size_t i = 0; i < arr->size; ++i) {
|
||||
json_free(arr->data[i]);
|
||||
}
|
||||
arr_destroy(arr);
|
||||
}
|
||||
|
||||
static inline void free_unused_obj(Obj* obj)
|
||||
{
|
||||
for (size_t i = 0; i < obj->size; ++i) {
|
||||
free(obj->data[i].key);
|
||||
json_free(obj->data[i].val);
|
||||
}
|
||||
obj_destroy(obj);
|
||||
}
|
||||
|
||||
JsonValue* json_parser_parse(JsonParser* p)
|
||||
{
|
||||
switch (p->curr_tok) {
|
||||
@ -188,23 +205,29 @@ JsonValue* json_parser_parse(JsonParser* p)
|
||||
arr_construct(&arr);
|
||||
{
|
||||
JsonValue* value = json_parser_parse(p);
|
||||
if (!value)
|
||||
if (!value) {
|
||||
free_unused_arr(&arr);
|
||||
return NULL;
|
||||
}
|
||||
arr_push(&arr, value);
|
||||
}
|
||||
while (p->curr_tok != TOK_EOF && p->curr_tok != ']') {
|
||||
if (p->curr_tok != ',') {
|
||||
fprintf(stderr, "error: json: expected ',' in array\n");
|
||||
free_unused_arr(&arr);
|
||||
return NULL;
|
||||
}
|
||||
lex(p);
|
||||
JsonValue* value = json_parser_parse(p);
|
||||
if (!value)
|
||||
if (!value) {
|
||||
free_unused_arr(&arr);
|
||||
return NULL;
|
||||
}
|
||||
arr_push(&arr, value);
|
||||
}
|
||||
if (p->curr_tok != ']') {
|
||||
fprintf(stderr, "error: json: expected ']' after array\n");
|
||||
free_unused_arr(&arr);
|
||||
return NULL;
|
||||
}
|
||||
lex(p);
|
||||
@ -218,52 +241,62 @@ JsonValue* json_parser_parse(JsonParser* p)
|
||||
{
|
||||
if (p->curr_tok != '"') {
|
||||
fprintf(stderr, "error: json: expected '\"' in kv\n");
|
||||
free_unused_obj(&obj);
|
||||
return NULL;
|
||||
}
|
||||
char* key = p->curr_val;
|
||||
lex(p);
|
||||
if (p->curr_tok != ':') {
|
||||
fprintf(stderr, "error: json: expected ':' in kv\n");
|
||||
free_unused_obj(&obj);
|
||||
return NULL;
|
||||
}
|
||||
lex(p);
|
||||
JsonValue* value = json_parser_parse(p);
|
||||
if (!value)
|
||||
if (!value) {
|
||||
free_unused_obj(&obj);
|
||||
return NULL;
|
||||
}
|
||||
obj_push(&obj, (KV) { key, value });
|
||||
}
|
||||
while (p->curr_tok != TOK_EOF && p->curr_tok != '}') {
|
||||
if (p->curr_tok != ',') {
|
||||
fprintf(stderr, "error: json: expected ',' in object\n");
|
||||
free_unused_obj(&obj);
|
||||
return NULL;
|
||||
}
|
||||
lex(p);
|
||||
|
||||
if (p->curr_tok != '"') {
|
||||
fprintf(stderr, "error: json: expected '\"' in kv\n");
|
||||
free_unused_obj(&obj);
|
||||
return NULL;
|
||||
}
|
||||
char* key = p->curr_val;
|
||||
lex(p);
|
||||
if (p->curr_tok != ':') {
|
||||
fprintf(stderr, "error: json: expected ':' in kv\n");
|
||||
free_unused_obj(&obj);
|
||||
return NULL;
|
||||
}
|
||||
lex(p);
|
||||
JsonValue* value = json_parser_parse(p);
|
||||
if (!value)
|
||||
if (!value) {
|
||||
free_unused_obj(&obj);
|
||||
return NULL;
|
||||
}
|
||||
obj_push(&obj, (KV) { key, value });
|
||||
}
|
||||
if (p->curr_tok != '}') {
|
||||
fprintf(stderr, "error: json: expected '}' after object\n");
|
||||
free_unused_obj(&obj);
|
||||
return NULL;
|
||||
}
|
||||
lex(p);
|
||||
return alloc((JsonValue) { .type = JsonType_Object, .obj_val = obj });
|
||||
}
|
||||
|
||||
fprintf(stderr, "error: json: unexpeted tok\n");
|
||||
fprintf(stderr, "error: json: unexpeted token\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -300,6 +333,7 @@ static inline void lex(JsonParser* p)
|
||||
case '0':
|
||||
lstep(p);
|
||||
p->curr_tok = TOK_NUMBER;
|
||||
p->curr_val = str_dup("0");
|
||||
return;
|
||||
}
|
||||
if ((p->ch >= '1' && p->ch <= '9') || p->ch == '.') {
|
||||
@ -315,14 +349,36 @@ static inline void lex(JsonParser* p)
|
||||
string_push(&value, p->ch);
|
||||
lstep(p);
|
||||
}
|
||||
// should be interned
|
||||
char* copy = string_copy(&value);
|
||||
|
||||
string_destroy(&value);
|
||||
|
||||
p->curr_tok = TOK_NUMBER;
|
||||
p->curr_val = copy;
|
||||
return;
|
||||
}
|
||||
if ((p->ch >= 'a' && p->ch <= 'z') || (p->ch >= 'A' && p->ch <= 'Z')) {
|
||||
String value;
|
||||
string_construct(&value);
|
||||
while (p->i < p->text_len
|
||||
&& ((p->ch >= 'a' && p->ch <= 'z')
|
||||
|| (p->ch >= 'A' && p->ch <= 'Z'))) {
|
||||
string_push(&value, p->ch);
|
||||
lstep(p);
|
||||
}
|
||||
if (strcmp(value.data, "null")) {
|
||||
p->curr_tok = TOK_NULL;
|
||||
} else if (strcmp(value.data, "false")) {
|
||||
p->curr_tok = TOK_FALSE;
|
||||
} else if (strcmp(value.data, "true")) {
|
||||
p->curr_tok = TOK_TRUE;
|
||||
} else {
|
||||
fprintf(
|
||||
stderr, "error: json: illegal keyword \"%s\"\n", value.data);
|
||||
p->curr_tok = TOK_ERROR;
|
||||
}
|
||||
string_destroy(&value);
|
||||
return;
|
||||
}
|
||||
if (p->ch == '"') {
|
||||
lstep(p);
|
||||
|
||||
@ -364,10 +420,9 @@ static inline void lex(JsonParser* p)
|
||||
}
|
||||
lstep(p);
|
||||
|
||||
// should be interned
|
||||
char* copy = string_copy(&value);
|
||||
|
||||
string_destroy(&value);
|
||||
|
||||
p->curr_tok = '"';
|
||||
p->curr_val = copy;
|
||||
return;
|
||||
|
@ -38,11 +38,16 @@ int main(void)
|
||||
http_server_set_user_ctx(server, &cx);
|
||||
|
||||
http_server_get(server, "/api/products/all", route_get_products_all);
|
||||
http_server_post(
|
||||
server, "/api/products/create", route_post_products_create);
|
||||
http_server_post(
|
||||
server, "/api/products/update", route_post_products_update);
|
||||
|
||||
http_server_get(
|
||||
server, "/product_editor/index.html", route_get_product_editor_html);
|
||||
http_server_get(server,
|
||||
"/product_editor/product_editor.js",
|
||||
route_get_product_editor_html);
|
||||
route_get_product_editor_js);
|
||||
|
||||
http_server_post(server, "/api/carts/purchase", route_post_carts_purchase);
|
||||
|
||||
|
@ -104,6 +104,15 @@ void receipts_one_res_destroy(ReceiptsOneRes* m)
|
||||
receipts_one_res_product_vec_destroy(&m->products);
|
||||
}
|
||||
|
||||
void products_create_req_destroy(ProductsCreateReq* m)
|
||||
{
|
||||
static_assert(sizeof(ProductsCreateReq) == 40, "model has changed");
|
||||
|
||||
free(m->name);
|
||||
free(m->description);
|
||||
free(m->barcode);
|
||||
}
|
||||
|
||||
char* user_to_json_string(const User* m)
|
||||
{
|
||||
static_assert(sizeof(User) == 40, "model has changed");
|
||||
@ -363,6 +372,31 @@ char* receipts_one_res_to_json_string(const ReceiptsOneRes* m)
|
||||
return result;
|
||||
}
|
||||
|
||||
char* products_create_req_to_json_string(const ProductsCreateReq* m)
|
||||
{
|
||||
static_assert(sizeof(ProductsCreateReq) == 40, "model has changed");
|
||||
|
||||
String string;
|
||||
string_construct(&string);
|
||||
string_pushf(&string,
|
||||
"{"
|
||||
"\"name\":\"%s\","
|
||||
"\"description\":\"%s\","
|
||||
"\"price_dkk_cent\":%ld,"
|
||||
"\"coord_id\":%ld,"
|
||||
"\"barcode\":\"%s\""
|
||||
"}",
|
||||
m->name,
|
||||
m->description,
|
||||
m->price_dkk_cent,
|
||||
m->coord_id,
|
||||
m->barcode);
|
||||
|
||||
char* result = string_copy(&string);
|
||||
string_destroy(&string);
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char* key;
|
||||
JsonType type;
|
||||
@ -456,7 +490,7 @@ int product_from_json(Product* m, const JsonValue* json)
|
||||
.description = GET_STR("description"),
|
||||
.price_dkk_cent = GET_INT("price_dkk_cent"),
|
||||
.coord_id = GET_INT("coord_id"),
|
||||
.barcode = GET_STR("y"),
|
||||
.barcode = GET_STR("barcode"),
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
@ -583,6 +617,29 @@ int receipts_one_res_from_json(ReceiptsOneRes* m, const JsonValue* json)
|
||||
PANIC("not implemented");
|
||||
}
|
||||
|
||||
int products_create_req_from_json(ProductsCreateReq* m, const JsonValue* json)
|
||||
{
|
||||
static_assert(sizeof(ProductsCreateReq) == 40, "model has changed");
|
||||
|
||||
ObjField fields[] = {
|
||||
{ "name", JsonType_String },
|
||||
{ "description", JsonType_String },
|
||||
{ "price_dkk_cent", JsonType_Number },
|
||||
{ "coord_id", JsonType_Number },
|
||||
{ "barcode", JsonType_String },
|
||||
};
|
||||
if (!OBJ_CONFORMS(json, fields))
|
||||
return -1;
|
||||
*m = (ProductsCreateReq) {
|
||||
.name = GET_STR("name"),
|
||||
.description = GET_STR("description"),
|
||||
.price_dkk_cent = GET_INT("price_dkk_cent"),
|
||||
.coord_id = GET_INT("coord_id"),
|
||||
.barcode = GET_STR("barcode"),
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_VEC_IMPL(ProductPrice, ProductPriceVec, product_price_vec, )
|
||||
DEFINE_VEC_IMPL(ReceiptProduct, ReceiptProductVec, receipt_product_vec, )
|
||||
DEFINE_VEC_IMPL(Receipt, ReceiptVec, receipt_vec, )
|
||||
|
@ -121,3 +121,13 @@ typedef struct {
|
||||
} ReceiptsOneRes;
|
||||
|
||||
void receipts_one_res_destroy(ReceiptsOneRes* model);
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
char* description;
|
||||
int64_t price_dkk_cent;
|
||||
int64_t coord_id;
|
||||
char* barcode;
|
||||
} ProductsCreateReq;
|
||||
|
||||
void products_create_req_destroy(ProductsCreateReq* model);
|
||||
|
@ -17,3 +17,4 @@ DEFINE_MODEL_JSON(SessionsLoginReq, sessions_login_req)
|
||||
DEFINE_MODEL_JSON(CartsPurchaseReq, carts_purchase_req)
|
||||
DEFINE_MODEL_JSON(ReceiptsOneResProduct, receipts_one_res_product)
|
||||
DEFINE_MODEL_JSON(ReceiptsOneRes, receipts_one_res)
|
||||
DEFINE_MODEL_JSON(ProductsCreateReq, products_create_req)
|
||||
|
Loading…
x
Reference in New Issue
Block a user