diff --git a/backend/prepare.sql b/backend/prepare.sql index 12758f5..12821e0 100644 --- a/backend/prepare.sql +++ b/backend/prepare.sql @@ -42,9 +42,12 @@ CREATE TABLE IF NOT EXISTS carts ( CREATE TABLE IF NOT EXISTS cart_items ( id INTEGER PRIMARY KEY, cart INTEGER NOT NULL, + product INTEGER NOT NULL, amount INTEGER NOT NULL, - FOREIGN KEY(cart) REFERENCES carts(id) + + FOREIGN KEY(cart) REFERENCES carts(id), + FOREIGN KEY(product) REFERENCES product(id) ); diff --git a/backend/src/controllers.h b/backend/src/controllers.h index 6f38c5c..87d7b4a 100644 --- a/backend/src/controllers.h +++ b/backend/src/controllers.h @@ -32,6 +32,8 @@ void route_get_not_found(HttpCtx* ctx); void route_get_products_all(HttpCtx* ctx); +void route_get_cart_items_from_session(HttpCtx* ctx); + void route_post_users_register(HttpCtx* ctx); void route_post_sessions_login(HttpCtx* ctx); diff --git a/backend/src/controllers/carts.c b/backend/src/controllers/carts.c new file mode 100644 index 0000000..3f560e4 --- /dev/null +++ b/backend/src/controllers/carts.c @@ -0,0 +1,42 @@ +#include "../controllers.h" +#include "../http_server.h" +#include "../models_json.h" +#include "../str_util.h" + +void route_get_cart_items_from_session(HttpCtx* ctx) +{ + Cx* cx = http_ctx_user_ctx(ctx); + const Session* session = middleware_session(ctx); + if (!session) + return; + + + CartItemVec cart_items; + cart_item_vec_construct(&cart_items); + + DbRes db_res = db_cart_items_with_user_id(cx->db, &cart_items, session->user_id); + if (db_res != DbRes_Ok) { + RESPOND_BAD_REQUEST(ctx, "Could not find cart for user"); + return; + } + + + String res; + string_construct(&res); + + string_push_str(&res, "{\"ok\":true,\"products\":["); + for (size_t i = 0; i < cart_items.size; ++i) { + if (i != 0) { + string_push_str(&res, ","); + } + char* json = cart_item_to_json_string(&cart_items.data[i]); + string_push_str(&res, json); + free(json); + } + string_push_str(&res, "]}"); + + + cart_item_vec_destroy(&cart_items); + RESPOND_JSON(ctx, 200, "%s", res.data); + string_destroy(&res); +} diff --git a/backend/src/controllers/sessions.c b/backend/src/controllers/sessions.c index 9f9dd15..5404cab 100644 --- a/backend/src/controllers/sessions.c +++ b/backend/src/controllers/sessions.c @@ -27,7 +27,7 @@ void route_post_sessions_login(HttpCtx* ctx) } User user; - DbRes db_res = db_user_from_email(cx->db, &user, req.email); + DbRes db_res = db_user_with_email(cx->db, &user, req.email); if (db_res == DbRes_NotFound) { RESPOND_BAD_REQUEST(ctx, "user with email not found"); goto l0_return; @@ -71,7 +71,7 @@ void route_get_sessions_user(HttpCtx* ctx) return; User user; - DbRes db_res = db_user_from_id(cx->db, &user, session->user_id); + DbRes db_res = db_user_with_id(cx->db, &user, session->user_id); if (db_res != DbRes_Ok) { RESPOND_BAD_REQUEST(ctx, "user not found"); return; diff --git a/backend/src/db.h b/backend/src/db.h index 63ef467..9770e62 100644 --- a/backend/src/db.h +++ b/backend/src/db.h @@ -2,9 +2,12 @@ #include "collection.h" #include "models.h" +#include DEFINE_VEC(int64_t, Ids, ids, 8) DEFINE_VEC(Product, ProductVec, product_vec, 32) +DEFINE_VEC(CartItem, CartItemVec, cart_item_vec, 32) + typedef enum { DbRes_Ok, @@ -17,7 +20,7 @@ typedef struct Db Db; /// `user.id` field is ignored. DbRes db_user_insert(Db* db, const User* user); /// `user` field is an out parameter. -DbRes db_user_from_id(Db* db, User* user, int64_t id); +DbRes db_user_with_id(Db* db, User* user, int64_t id); /// Expects `ids` to be constructed. @@ -25,7 +28,10 @@ DbRes db_users_with_email(Db* db, Ids* ids, const char* email); /// `user` is an out parameter. -DbRes db_user_from_email(Db* db, User* user, const char* email); +DbRes db_user_with_email(Db* db, User* user, const char* email); /// Expects `vec` to be constructed. DbRes db_product_all(Db* db, ProductVec* vec); + +DbRes db_cart_items_with_user_id(Db* db, CartItemVec* vec, int64_t user_id); + diff --git a/backend/src/db_sqlite.c b/backend/src/db_sqlite.c index 3fd621a..a0d0633 100644 --- a/backend/src/db_sqlite.c +++ b/backend/src/db_sqlite.c @@ -4,6 +4,7 @@ #include "str_util.h" #include #include +#include #include static inline char* get_str_safe(sqlite3_stmt* stmt, int col) @@ -100,7 +101,7 @@ l0_return: return res; } -DbRes db_user_from_id(Db* db, User* user, int64_t id) +DbRes db_user_with_id(Db* db, User* user, int64_t id) { static_assert(sizeof(User) == 40, "model has changed"); @@ -118,7 +119,6 @@ DbRes db_user_from_id(Db* db, User* user, int64_t id) int step_res = sqlite3_step(stmt); if (step_res == SQLITE_DONE) { res = DbRes_NotFound; - puts("didn't find user"); goto l0_return; } else if (step_res != SQLITE_ROW) { fprintf(stderr, "error: %s\n", sqlite3_errmsg(connection)); @@ -173,7 +173,7 @@ l0_return: return res; } -DbRes db_user_from_email(Db* db, User* user, const char* email) +DbRes db_user_with_email(Db* db, User* user, const char* email) { static_assert(sizeof(User) == 40, "model has changed"); @@ -263,3 +263,65 @@ l0_return: DISCONNECT; return res; } + + +DbRes db_cart_items_with_user_id(Db* db, CartItemVec* vec, int64_t user_id) { + static_assert(sizeof(Cart) == 16, "model has changed"); + static_assert(sizeof(CartItem) == 32, "model has changed"); + + sqlite3* connection; + CONNECT; + DbRes res; + + sqlite3_stmt* stmt; + int sqlite_res = sqlite3_prepare_v2(connection, + "SELECT id " + " FROM carts WHERE user = ?", + -1, &stmt, NULL); + if (sqlite_res != SQLITE_OK) { + fprintf(stderr, "error: %s\n at %s:%d\n", sqlite3_errmsg(connection), + __func__, __LINE__); + res = DbRes_Error; + goto l0_return; + } + sqlite3_bind_int64(stmt, 1, user_id); + + int step_res = sqlite3_step(stmt); + if (step_res == SQLITE_DONE) { + res = DbRes_NotFound; + goto l0_return; + } else if (step_res != SQLITE_ROW) { + fprintf(stderr, "error: %s\n", sqlite3_errmsg(connection)); + res = DbRes_Error; + goto l0_return; + } + int64_t cart_id = GET_INT(0); + + sqlite_res = sqlite3_prepare_v2( + connection, "SELECT id, cart, product, amount FROM cart_items WHERE cart = ?", -1, &stmt, NULL); + sqlite3_bind_int64(stmt, 1, cart_id); + + while ((sqlite_res = sqlite3_step(stmt)) == SQLITE_ROW) { + CartItem cart_item = { + .id = GET_INT(0), + .cart_id = GET_INT(1), + .product_id = GET_INT(2), + .amount = GET_INT(3), + }; + cart_item_vec_push(vec, cart_item); + } + if (sqlite_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; + +} + diff --git a/backend/src/main.c b/backend/src/main.c index 20e2e2c..301f0a4 100644 --- a/backend/src/main.c +++ b/backend/src/main.c @@ -43,6 +43,8 @@ int main(void) http_server_get(server, "/api/products/all", route_get_products_all); + http_server_get(server, "/api/cart", route_get_cart_items_from_session); + http_server_post(server, "/api/users/register", route_post_users_register); http_server_post(server, "/api/sessions/login", route_post_sessions_login); http_server_post( diff --git a/backend/src/models.c b/backend/src/models.c index 9d5e1b4..11ef2ec 100644 --- a/backend/src/models.c +++ b/backend/src/models.c @@ -47,7 +47,7 @@ void cart_destroy(Cart* m) void cart_item_destroy(CartItem* m) { - static_assert(sizeof(CartItem) == 24, "model has changed"); + static_assert(sizeof(CartItem) == 32, "model has changed"); (void)m; } @@ -170,7 +170,7 @@ char* cart_to_json_string(const Cart* m) char* cart_item_to_json_string(const CartItem* m) { - static_assert(sizeof(CartItem) == 24, "model has changed"); + static_assert(sizeof(CartItem) == 32, "model has changed"); String string; string_construct(&string); @@ -178,9 +178,10 @@ char* cart_item_to_json_string(const CartItem* m) "{" "\"id\":%ld," "\"cart_id\":%ld," + "\"product_id\":%ld," "\"amount\":%ld" "}", - m->id, m->cart_id, m->amount); + m->id, m->cart_id, m->product_id, m->amount); char* result = string_copy(&string); string_destroy(&string); @@ -354,11 +355,12 @@ int cart_from_json(Cart* m, const JsonValue* json) int cart_item_from_json(CartItem* m, const JsonValue* json) { - static_assert(sizeof(CartItem) == 24, "model has changed"); + static_assert(sizeof(CartItem) == 32, "model has changed"); ObjField fields[] = { { "id", JsonType_Number }, { "cart_id", JsonType_Number }, + { "product_id", JsonType_Number }, { "amount", JsonType_Number }, }; if (!obj_conforms(json, fields, sizeof(fields) / sizeof(fields[0]))) @@ -366,6 +368,7 @@ int cart_item_from_json(CartItem* m, const JsonValue* json) *m = (CartItem) { .id = GET_INT("id"), .cart_id = GET_INT("cart_id"), + .product_id = GET_INT("product_id"), .amount = GET_INT("amount"), }; return 0; diff --git a/backend/src/models.h b/backend/src/models.h index fd59deb..d62b979 100644 --- a/backend/src/models.h +++ b/backend/src/models.h @@ -39,6 +39,7 @@ typedef struct { typedef struct { int64_t id; int64_t cart_id; + int64_t product_id; int64_t amount; } CartItem;