mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-27 16:24:07 +02:00
add coords
This commit is contained in:
parent
cfc73f0868
commit
fb26face86
@ -38,6 +38,8 @@ void route_get_not_found(HttpCtx* ctx);
|
|||||||
void route_get_products_all(HttpCtx* ctx);
|
void route_get_products_all(HttpCtx* ctx);
|
||||||
void route_post_products_create(HttpCtx* ctx);
|
void route_post_products_create(HttpCtx* ctx);
|
||||||
void route_post_products_update(HttpCtx* ctx);
|
void route_post_products_update(HttpCtx* ctx);
|
||||||
|
void route_get_products_coords(HttpCtx* ctx);
|
||||||
|
void route_post_products_set_coords(HttpCtx* ctx);
|
||||||
void route_post_products_set_image(HttpCtx* ctx);
|
void route_post_products_set_image(HttpCtx* ctx);
|
||||||
void route_get_products_image_png(HttpCtx* ctx);
|
void route_get_products_image_png(HttpCtx* ctx);
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "../models/models_json.h"
|
#include "../models/models_json.h"
|
||||||
#include "../utils/str.h"
|
#include "../utils/str.h"
|
||||||
#include "controllers.h"
|
#include "controllers.h"
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
void route_get_products_all(HttpCtx* ctx)
|
void route_get_products_all(HttpCtx* ctx)
|
||||||
@ -82,10 +83,8 @@ void route_post_products_update(HttpCtx* ctx)
|
|||||||
Cx* cx = http_ctx_user_ctx(ctx);
|
Cx* cx = http_ctx_user_ctx(ctx);
|
||||||
|
|
||||||
const char* body_str = http_ctx_req_body_str(ctx);
|
const char* body_str = http_ctx_req_body_str(ctx);
|
||||||
printf("body_str = '%s'\n", body_str);
|
|
||||||
|
|
||||||
JsonValue* body_json = json_parse(body_str, strlen(body_str));
|
JsonValue* body_json = json_parse(body_str, strlen(body_str));
|
||||||
printf("body_json = %p\n", (void*)body_json);
|
|
||||||
|
|
||||||
if (!body_json) {
|
if (!body_json) {
|
||||||
RESPOND_BAD_REQUEST(ctx, "bad request");
|
RESPOND_BAD_REQUEST(ctx, "bad request");
|
||||||
@ -94,7 +93,6 @@ void route_post_products_update(HttpCtx* ctx)
|
|||||||
|
|
||||||
Product product;
|
Product product;
|
||||||
int parse_result = product_from_json(&product, body_json);
|
int parse_result = product_from_json(&product, body_json);
|
||||||
printf("parse_result = %d\n", parse_result);
|
|
||||||
json_free(body_json);
|
json_free(body_json);
|
||||||
if (parse_result != 0) {
|
if (parse_result != 0) {
|
||||||
RESPOND_BAD_REQUEST(ctx, "bad request");
|
RESPOND_BAD_REQUEST(ctx, "bad request");
|
||||||
@ -113,6 +111,102 @@ l0_return:
|
|||||||
product_destroy(&product);
|
product_destroy(&product);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void route_get_products_coords(HttpCtx* ctx)
|
||||||
|
{
|
||||||
|
Cx* cx = http_ctx_user_ctx(ctx);
|
||||||
|
|
||||||
|
const char* query = http_ctx_req_query(ctx);
|
||||||
|
if (!query) {
|
||||||
|
RESPOND_BAD_REQUEST(ctx, "no product_id parameter");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HttpQueryParams* params = http_parse_query_params(query);
|
||||||
|
char* product_id_str = http_query_params_get(params, "product_id");
|
||||||
|
http_query_params_free(params);
|
||||||
|
if (!product_id_str) {
|
||||||
|
RESPOND_BAD_REQUEST(ctx, "no product_id parameter");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t product_id = strtol(product_id_str, NULL, 10);
|
||||||
|
free(product_id_str);
|
||||||
|
|
||||||
|
Coord coord;
|
||||||
|
DbRes db_res = db_coord_with_product_id(cx->db, &coord, product_id);
|
||||||
|
if (db_res == DbRes_NotFound) {
|
||||||
|
RESPOND_JSON(ctx, 200, "{\"ok\":true,\"found\":false}");
|
||||||
|
return;
|
||||||
|
} else if (db_res != DbRes_Ok) {
|
||||||
|
RESPOND_SERVER_ERROR(ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* coord_json = coord_to_json_string(&coord);
|
||||||
|
|
||||||
|
RESPOND_JSON(
|
||||||
|
ctx, 200, "{\"ok\":true,\"found\":true,\"coords\":%s}", coord_json);
|
||||||
|
free(coord_json);
|
||||||
|
coord_destroy(&coord);
|
||||||
|
}
|
||||||
|
|
||||||
|
void route_post_products_set_coords(HttpCtx* ctx)
|
||||||
|
{
|
||||||
|
Cx* cx = http_ctx_user_ctx(ctx);
|
||||||
|
|
||||||
|
const char* body_str = http_ctx_req_body_str(ctx);
|
||||||
|
JsonValue* body_json = json_parse(body_str, strlen(body_str));
|
||||||
|
if (!body_json) {
|
||||||
|
RESPOND_BAD_REQUEST(ctx, "bad request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProductsCoordsSetReq req;
|
||||||
|
int parse_result = products_coords_set_req_from_json(&req, body_json);
|
||||||
|
json_free(body_json);
|
||||||
|
if (parse_result != 0) {
|
||||||
|
RESPOND_BAD_REQUEST(ctx, "bad request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Product product;
|
||||||
|
DbRes db_res = db_product_with_id(cx->db, &product, req.product_id);
|
||||||
|
if (db_res == DbRes_NotFound) {
|
||||||
|
RESPOND_BAD_REQUEST(ctx, "not found");
|
||||||
|
goto l0_return;
|
||||||
|
} else if (db_res != DbRes_Ok) {
|
||||||
|
RESPOND_SERVER_ERROR(ctx);
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Coord coord = {
|
||||||
|
.id = 0,
|
||||||
|
.x = req.x,
|
||||||
|
.y = req.y,
|
||||||
|
};
|
||||||
|
|
||||||
|
int64_t coord_id;
|
||||||
|
db_res = db_coord_insert(cx->db, &coord, &coord_id);
|
||||||
|
if (db_res != DbRes_Ok) {
|
||||||
|
RESPOND_SERVER_ERROR(ctx);
|
||||||
|
goto l1_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
product.coord_id = coord_id;
|
||||||
|
|
||||||
|
db_res = db_product_update(cx->db, &product);
|
||||||
|
if (db_res != DbRes_Ok) {
|
||||||
|
RESPOND_SERVER_ERROR(ctx);
|
||||||
|
goto l1_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RESPOND_JSON(ctx, 200, "{\"ok\":true}");
|
||||||
|
l1_return:
|
||||||
|
coord_destroy(&coord);
|
||||||
|
products_coords_set_req_destroy(&req);
|
||||||
|
l0_return:
|
||||||
|
product_destroy(&product);
|
||||||
|
}
|
||||||
|
|
||||||
void route_post_products_set_image(HttpCtx* ctx)
|
void route_post_products_set_image(HttpCtx* ctx)
|
||||||
{
|
{
|
||||||
Cx* cx = http_ctx_user_ctx(ctx);
|
Cx* cx = http_ctx_user_ctx(ctx);
|
||||||
|
@ -25,6 +25,7 @@ DbRes db_user_update(Db* db, const User* user);
|
|||||||
/// `user` field is an out parameter.
|
/// `user` field is an out parameter.
|
||||||
DbRes db_user_with_id(Db* db, User* user, int64_t id);
|
DbRes db_user_with_id(Db* db, User* user, int64_t id);
|
||||||
|
|
||||||
|
/// `exists` field is an out parameter.
|
||||||
DbRes db_user_with_email_exists(Db* db, bool* exists, const char* email);
|
DbRes db_user_with_email_exists(Db* db, bool* exists, const char* email);
|
||||||
|
|
||||||
/// `user` is an out parameter.
|
/// `user` is an out parameter.
|
||||||
@ -42,6 +43,12 @@ DbRes db_product_with_id(Db* db, Product* product, int64_t id);
|
|||||||
/// Expects `vec` to be constructed.
|
/// Expects `vec` to be constructed.
|
||||||
DbRes db_product_all(Db* db, ProductVec* vec);
|
DbRes db_product_all(Db* db, ProductVec* vec);
|
||||||
|
|
||||||
|
/// `coord.id` are ignored.
|
||||||
|
DbRes db_coord_insert(Db* db, const Coord* coord, int64_t* id);
|
||||||
|
|
||||||
|
/// `coord` is an out parameter.
|
||||||
|
DbRes db_coord_with_product_id(Db* db, Coord* coord, int64_t product_id);
|
||||||
|
|
||||||
/// `product_price` is an out parameter.
|
/// `product_price` is an out parameter.
|
||||||
DbRes db_product_price_of_product(
|
DbRes db_product_price_of_product(
|
||||||
Db* db, ProductPrice* product_price, int64_t product_id);
|
Db* db, ProductPrice* product_price, int64_t product_id);
|
||||||
|
@ -472,6 +472,100 @@ l0_return:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `coord.id` are ignored.
|
||||||
|
DbRes db_coord_insert(Db* db, const Coord* coord, int64_t* id)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(Coord) == 24, "model has changed");
|
||||||
|
|
||||||
|
sqlite3* connection;
|
||||||
|
CONNECT;
|
||||||
|
DbRes res;
|
||||||
|
|
||||||
|
sqlite3_stmt* stmt;
|
||||||
|
int prepare_res = sqlite3_prepare_v2(connection,
|
||||||
|
"INSERT INTO coords"
|
||||||
|
" (x, y)"
|
||||||
|
" VALUES (?, ?)",
|
||||||
|
-1,
|
||||||
|
&stmt,
|
||||||
|
NULL);
|
||||||
|
if (prepare_res != SQLITE_OK) {
|
||||||
|
REPORT_SQLITE3_ERROR();
|
||||||
|
res = DbRes_Error;
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_bind_int64(stmt, 1, coord->x);
|
||||||
|
sqlite3_bind_int64(stmt, 2, coord->y);
|
||||||
|
|
||||||
|
int step_res = sqlite3_step(stmt);
|
||||||
|
if (step_res != SQLITE_DONE) {
|
||||||
|
REPORT_SQLITE3_ERROR();
|
||||||
|
res = DbRes_Error;
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t coord_id = sqlite3_last_insert_rowid(connection);
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
*id = coord_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = DbRes_Ok;
|
||||||
|
l0_return:
|
||||||
|
if (stmt)
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
DISCONNECT;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
DbRes db_coord_with_product_id(Db* db, Coord* coord, int64_t product_id)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(Coord) == 24, "model has changed");
|
||||||
|
|
||||||
|
sqlite3* connection;
|
||||||
|
CONNECT;
|
||||||
|
DbRes res;
|
||||||
|
|
||||||
|
sqlite3_stmt* stmt;
|
||||||
|
int prepare_res = sqlite3_prepare_v2(connection,
|
||||||
|
"SELECT coords.id, coords.x, coords.y"
|
||||||
|
" FROM coords"
|
||||||
|
" JOIN products ON products.coord = coords.id"
|
||||||
|
" WHERE products.id = ?",
|
||||||
|
-1,
|
||||||
|
&stmt,
|
||||||
|
NULL);
|
||||||
|
if (prepare_res != SQLITE_OK) {
|
||||||
|
REPORT_SQLITE3_ERROR();
|
||||||
|
res = DbRes_Error;
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
sqlite3_bind_int64(stmt, 1, product_id);
|
||||||
|
|
||||||
|
int step_res = sqlite3_step(stmt);
|
||||||
|
if (step_res == SQLITE_DONE) {
|
||||||
|
res = DbRes_NotFound;
|
||||||
|
goto l0_return;
|
||||||
|
} else if (step_res != SQLITE_ROW) {
|
||||||
|
REPORT_SQLITE3_ERROR();
|
||||||
|
res = DbRes_Error;
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
*coord = (Coord){
|
||||||
|
.id = GET_INT(0),
|
||||||
|
.x = GET_INT(1),
|
||||||
|
.y = GET_INT(2),
|
||||||
|
},
|
||||||
|
|
||||||
|
res = DbRes_Ok;
|
||||||
|
l0_return:
|
||||||
|
if (stmt)
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
DISCONNECT;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static inline DbRes get_product_price_from_product_id(
|
static inline DbRes get_product_price_from_product_id(
|
||||||
sqlite3* connection, int64_t product_id, int64_t* price)
|
sqlite3* connection, int64_t product_id, int64_t* price)
|
||||||
{
|
{
|
||||||
|
@ -40,6 +40,9 @@ int main(void)
|
|||||||
server, "/api/products/create", route_post_products_create);
|
server, "/api/products/create", route_post_products_create);
|
||||||
http_server_post(
|
http_server_post(
|
||||||
server, "/api/products/update", route_post_products_update);
|
server, "/api/products/update", route_post_products_update);
|
||||||
|
http_server_get(server, "/api/products/coords", route_get_products_coords);
|
||||||
|
http_server_post(
|
||||||
|
server, "/api/products/set_coords", route_post_products_set_coords);
|
||||||
http_server_post(
|
http_server_post(
|
||||||
server, "/api/products/set-image", route_post_products_set_image);
|
server, "/api/products/set-image", route_post_products_set_image);
|
||||||
http_server_get(
|
http_server_get(
|
||||||
|
@ -113,6 +113,13 @@ void products_create_req_destroy(ProductsCreateReq* m)
|
|||||||
free(m->barcode);
|
free(m->barcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void products_coords_set_req_destroy(ProductsCoordsSetReq* model)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(ProductsCoordsSetReq) == 24, "model has changed");
|
||||||
|
|
||||||
|
(void)model;
|
||||||
|
}
|
||||||
|
|
||||||
char* user_to_json_string(const User* m)
|
char* user_to_json_string(const User* m)
|
||||||
{
|
{
|
||||||
static_assert(sizeof(User) == 40, "model has changed");
|
static_assert(sizeof(User) == 40, "model has changed");
|
||||||
@ -397,6 +404,27 @@ char* products_create_req_to_json_string(const ProductsCreateReq* m)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* products_coords_set_req_to_json_string(const ProductsCoordsSetReq* m)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(ProductsCoordsSetReq) == 24, "model has changed");
|
||||||
|
|
||||||
|
String string;
|
||||||
|
string_construct(&string);
|
||||||
|
string_pushf(&string,
|
||||||
|
"{"
|
||||||
|
"\"product_id\":%ld,"
|
||||||
|
"\"x\":%ld,"
|
||||||
|
"\"y\":%ld"
|
||||||
|
"}",
|
||||||
|
m->product_id,
|
||||||
|
m->x,
|
||||||
|
m->y);
|
||||||
|
|
||||||
|
char* result = string_copy(&string);
|
||||||
|
string_destroy(&string);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char* key;
|
const char* key;
|
||||||
JsonType type;
|
JsonType type;
|
||||||
@ -639,6 +667,25 @@ int products_create_req_from_json(ProductsCreateReq* m, const JsonValue* json)
|
|||||||
};
|
};
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
int products_coords_set_req_from_json(
|
||||||
|
ProductsCoordsSetReq* m, const JsonValue* json)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(ProductsCoordsSetReq) == 24, "model has changed");
|
||||||
|
|
||||||
|
ObjField fields[] = {
|
||||||
|
{ "product_id", JsonType_Number },
|
||||||
|
{ "x", JsonType_Number },
|
||||||
|
{ "y", JsonType_Number },
|
||||||
|
};
|
||||||
|
if (!OBJ_CONFORMS(json, fields))
|
||||||
|
return -1;
|
||||||
|
*m = (ProductsCoordsSetReq) {
|
||||||
|
.product_id = GET_INT("product_id"),
|
||||||
|
.x = GET_INT("x"),
|
||||||
|
.y = GET_INT("y"),
|
||||||
|
};
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
DEFINE_VEC_IMPL(ProductPrice, ProductPriceVec, product_price_vec, )
|
DEFINE_VEC_IMPL(ProductPrice, ProductPriceVec, product_price_vec, )
|
||||||
DEFINE_VEC_IMPL(ReceiptProduct, ReceiptProductVec, receipt_product_vec, )
|
DEFINE_VEC_IMPL(ReceiptProduct, ReceiptProductVec, receipt_product_vec, )
|
||||||
|
@ -131,3 +131,11 @@ typedef struct {
|
|||||||
} ProductsCreateReq;
|
} ProductsCreateReq;
|
||||||
|
|
||||||
void products_create_req_destroy(ProductsCreateReq* model);
|
void products_create_req_destroy(ProductsCreateReq* model);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int64_t product_id;
|
||||||
|
int64_t x;
|
||||||
|
int64_t y;
|
||||||
|
} ProductsCoordsSetReq;
|
||||||
|
|
||||||
|
void products_coords_set_req_destroy(ProductsCoordsSetReq* model);
|
||||||
|
@ -18,3 +18,4 @@ DEFINE_MODEL_JSON(CartsPurchaseReq, carts_purchase_req)
|
|||||||
DEFINE_MODEL_JSON(ReceiptsOneResProduct, receipts_one_res_product)
|
DEFINE_MODEL_JSON(ReceiptsOneResProduct, receipts_one_res_product)
|
||||||
DEFINE_MODEL_JSON(ReceiptsOneRes, receipts_one_res)
|
DEFINE_MODEL_JSON(ReceiptsOneRes, receipts_one_res)
|
||||||
DEFINE_MODEL_JSON(ProductsCreateReq, products_create_req)
|
DEFINE_MODEL_JSON(ProductsCreateReq, products_create_req)
|
||||||
|
DEFINE_MODEL_JSON(ProductsCoordsSetReq, products_coords_set_req)
|
||||||
|
@ -67,6 +67,8 @@ Deno.test("test backend", async (t) => {
|
|||||||
|
|
||||||
await testCartsAndReceipts(t, token!);
|
await testCartsAndReceipts(t, token!);
|
||||||
|
|
||||||
|
await testProductsCoords(t);
|
||||||
|
|
||||||
await t.step("test /api/sessions/logout", async () => {
|
await t.step("test /api/sessions/logout", async () => {
|
||||||
const logoutRes = await post<{ ok: boolean }>(
|
const logoutRes = await post<{ ok: boolean }>(
|
||||||
"/api/sessions/logout",
|
"/api/sessions/logout",
|
||||||
@ -154,6 +156,72 @@ async function testCartsAndReceipts(t: Deno.TestContext, token: string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function testProductsCoords(t: Deno.TestContext) {
|
||||||
|
const productId = 1;
|
||||||
|
let coords: { x: number; y: number } | null = null;
|
||||||
|
|
||||||
|
await t.step("test /api/products/coords", async () => {
|
||||||
|
const res = await get<{
|
||||||
|
ok: boolean;
|
||||||
|
found: boolean;
|
||||||
|
coords: { x: number; y: number };
|
||||||
|
}>(
|
||||||
|
`/api/products/coords?product_id=${productId}`,
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
|
||||||
|
// console.log(res);
|
||||||
|
assertEquals(res.ok, true);
|
||||||
|
if (res.found) {
|
||||||
|
coords = res.coords;
|
||||||
|
} else {
|
||||||
|
coords = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await t.step("test /api/products/set_coords", async () => {
|
||||||
|
const res = await post<{ ok: boolean }>(
|
||||||
|
"/api/products/set_coords",
|
||||||
|
{
|
||||||
|
product_id: productId,
|
||||||
|
x: 1,
|
||||||
|
y: 2,
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
|
||||||
|
// console.log(res);
|
||||||
|
assertEquals(res.ok, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
await t.step("test /api/products/coords", async () => {
|
||||||
|
const res = await get<{
|
||||||
|
ok: boolean;
|
||||||
|
found: true;
|
||||||
|
coords: { x: number; y: number };
|
||||||
|
}>(
|
||||||
|
`/api/products/coords?product_id=${productId}`,
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
|
||||||
|
// console.log(res);
|
||||||
|
assertEquals(res.ok, true);
|
||||||
|
assertEquals(res.found, true);
|
||||||
|
assertEquals(res.coords.x, 1);
|
||||||
|
assertEquals(res.coords.y, 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (coords !== null) {
|
||||||
|
const res = await post<{ ok: boolean }>(
|
||||||
|
"/api/products/set_coords",
|
||||||
|
{ product_id: productId, ...coords as { x: number; y: number } },
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
// console.log(res);
|
||||||
|
assertEquals(res.ok, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type SessionUser = { id: number; email: string; balance_dkk_cent: number };
|
type SessionUser = { id: number; email: string; balance_dkk_cent: number };
|
||||||
|
|
||||||
async function sessionUser(
|
async function sessionUser(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user