mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-27 08:24:05 +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_post_products_create(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_get_products_image_png(HttpCtx* ctx);
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "../models/models_json.h"
|
||||
#include "../utils/str.h"
|
||||
#include "controllers.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
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);
|
||||
|
||||
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));
|
||||
printf("body_json = %p\n", (void*)body_json);
|
||||
|
||||
if (!body_json) {
|
||||
RESPOND_BAD_REQUEST(ctx, "bad request");
|
||||
@ -94,7 +93,6 @@ void route_post_products_update(HttpCtx* ctx)
|
||||
|
||||
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");
|
||||
@ -113,6 +111,102 @@ l0_return:
|
||||
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)
|
||||
{
|
||||
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.
|
||||
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);
|
||||
|
||||
/// `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.
|
||||
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.
|
||||
DbRes db_product_price_of_product(
|
||||
Db* db, ProductPrice* product_price, int64_t product_id);
|
||||
|
@ -472,6 +472,100 @@ l0_return:
|
||||
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(
|
||||
sqlite3* connection, int64_t product_id, int64_t* price)
|
||||
{
|
||||
|
@ -40,6 +40,9 @@ int main(void)
|
||||
server, "/api/products/create", route_post_products_create);
|
||||
http_server_post(
|
||||
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(
|
||||
server, "/api/products/set-image", route_post_products_set_image);
|
||||
http_server_get(
|
||||
|
@ -113,6 +113,13 @@ void products_create_req_destroy(ProductsCreateReq* m)
|
||||
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)
|
||||
{
|
||||
static_assert(sizeof(User) == 40, "model has changed");
|
||||
@ -397,6 +404,27 @@ char* products_create_req_to_json_string(const ProductsCreateReq* m)
|
||||
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 {
|
||||
const char* key;
|
||||
JsonType type;
|
||||
@ -639,6 +667,25 @@ int products_create_req_from_json(ProductsCreateReq* m, const JsonValue* json)
|
||||
};
|
||||
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(ReceiptProduct, ReceiptProductVec, receipt_product_vec, )
|
||||
|
@ -131,3 +131,11 @@ typedef struct {
|
||||
} ProductsCreateReq;
|
||||
|
||||
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(ReceiptsOneRes, receipts_one_res)
|
||||
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 testProductsCoords(t);
|
||||
|
||||
await t.step("test /api/sessions/logout", async () => {
|
||||
const logoutRes = await post<{ ok: boolean }>(
|
||||
"/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 };
|
||||
|
||||
async function sessionUser(
|
||||
|
Loading…
x
Reference in New Issue
Block a user