mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-28 08:44:06 +02:00
implement api/cart
This commit is contained in:
parent
70b8244e62
commit
b486bb7970
@ -42,9 +42,12 @@ CREATE TABLE IF NOT EXISTS carts (
|
|||||||
CREATE TABLE IF NOT EXISTS cart_items (
|
CREATE TABLE IF NOT EXISTS cart_items (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
cart INTEGER NOT NULL,
|
cart INTEGER NOT NULL,
|
||||||
|
product INTEGER NOT NULL,
|
||||||
amount 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)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,6 +32,8 @@ void route_get_not_found(HttpCtx* ctx);
|
|||||||
|
|
||||||
void route_get_products_all(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_users_register(HttpCtx* ctx);
|
||||||
|
|
||||||
void route_post_sessions_login(HttpCtx* ctx);
|
void route_post_sessions_login(HttpCtx* ctx);
|
||||||
|
42
backend/src/controllers/carts.c
Normal file
42
backend/src/controllers/carts.c
Normal file
@ -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);
|
||||||
|
}
|
@ -27,7 +27,7 @@ void route_post_sessions_login(HttpCtx* ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
User user;
|
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) {
|
if (db_res == DbRes_NotFound) {
|
||||||
RESPOND_BAD_REQUEST(ctx, "user with email not found");
|
RESPOND_BAD_REQUEST(ctx, "user with email not found");
|
||||||
goto l0_return;
|
goto l0_return;
|
||||||
@ -71,7 +71,7 @@ void route_get_sessions_user(HttpCtx* ctx)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
User user;
|
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) {
|
if (db_res != DbRes_Ok) {
|
||||||
RESPOND_BAD_REQUEST(ctx, "user not found");
|
RESPOND_BAD_REQUEST(ctx, "user not found");
|
||||||
return;
|
return;
|
||||||
|
@ -2,9 +2,12 @@
|
|||||||
|
|
||||||
#include "collection.h"
|
#include "collection.h"
|
||||||
#include "models.h"
|
#include "models.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
DEFINE_VEC(int64_t, Ids, ids, 8)
|
DEFINE_VEC(int64_t, Ids, ids, 8)
|
||||||
DEFINE_VEC(Product, ProductVec, product_vec, 32)
|
DEFINE_VEC(Product, ProductVec, product_vec, 32)
|
||||||
|
DEFINE_VEC(CartItem, CartItemVec, cart_item_vec, 32)
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DbRes_Ok,
|
DbRes_Ok,
|
||||||
@ -17,7 +20,7 @@ typedef struct Db Db;
|
|||||||
/// `user.id` field is ignored.
|
/// `user.id` field is ignored.
|
||||||
DbRes db_user_insert(Db* db, const User* user);
|
DbRes db_user_insert(Db* db, const User* user);
|
||||||
/// `user` field is an out parameter.
|
/// `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.
|
/// 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.
|
/// `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.
|
/// Expects `vec` to be constructed.
|
||||||
DbRes db_product_all(Db* db, ProductVec* vec);
|
DbRes db_product_all(Db* db, ProductVec* vec);
|
||||||
|
|
||||||
|
DbRes db_cart_items_with_user_id(Db* db, CartItemVec* vec, int64_t user_id);
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "str_util.h"
|
#include "str_util.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
static inline char* get_str_safe(sqlite3_stmt* stmt, int col)
|
static inline char* get_str_safe(sqlite3_stmt* stmt, int col)
|
||||||
@ -100,7 +101,7 @@ l0_return:
|
|||||||
return res;
|
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");
|
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);
|
int step_res = sqlite3_step(stmt);
|
||||||
if (step_res == SQLITE_DONE) {
|
if (step_res == SQLITE_DONE) {
|
||||||
res = DbRes_NotFound;
|
res = DbRes_NotFound;
|
||||||
puts("didn't find user");
|
|
||||||
goto l0_return;
|
goto l0_return;
|
||||||
} else if (step_res != SQLITE_ROW) {
|
} else if (step_res != SQLITE_ROW) {
|
||||||
fprintf(stderr, "error: %s\n", sqlite3_errmsg(connection));
|
fprintf(stderr, "error: %s\n", sqlite3_errmsg(connection));
|
||||||
@ -173,7 +173,7 @@ l0_return:
|
|||||||
return res;
|
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");
|
static_assert(sizeof(User) == 40, "model has changed");
|
||||||
|
|
||||||
@ -263,3 +263,65 @@ l0_return:
|
|||||||
DISCONNECT;
|
DISCONNECT;
|
||||||
return res;
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,8 @@ int main(void)
|
|||||||
|
|
||||||
http_server_get(server, "/api/products/all", route_get_products_all);
|
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/users/register", route_post_users_register);
|
||||||
http_server_post(server, "/api/sessions/login", route_post_sessions_login);
|
http_server_post(server, "/api/sessions/login", route_post_sessions_login);
|
||||||
http_server_post(
|
http_server_post(
|
||||||
|
@ -47,7 +47,7 @@ void cart_destroy(Cart* m)
|
|||||||
|
|
||||||
void cart_item_destroy(CartItem* 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;
|
(void)m;
|
||||||
}
|
}
|
||||||
@ -170,7 +170,7 @@ char* cart_to_json_string(const Cart* m)
|
|||||||
|
|
||||||
char* cart_item_to_json_string(const CartItem* 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 string;
|
||||||
string_construct(&string);
|
string_construct(&string);
|
||||||
@ -178,9 +178,10 @@ char* cart_item_to_json_string(const CartItem* m)
|
|||||||
"{"
|
"{"
|
||||||
"\"id\":%ld,"
|
"\"id\":%ld,"
|
||||||
"\"cart_id\":%ld,"
|
"\"cart_id\":%ld,"
|
||||||
|
"\"product_id\":%ld,"
|
||||||
"\"amount\":%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);
|
char* result = string_copy(&string);
|
||||||
string_destroy(&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)
|
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[] = {
|
ObjField fields[] = {
|
||||||
{ "id", JsonType_Number },
|
{ "id", JsonType_Number },
|
||||||
{ "cart_id", JsonType_Number },
|
{ "cart_id", JsonType_Number },
|
||||||
|
{ "product_id", JsonType_Number },
|
||||||
{ "amount", JsonType_Number },
|
{ "amount", JsonType_Number },
|
||||||
};
|
};
|
||||||
if (!obj_conforms(json, fields, sizeof(fields) / sizeof(fields[0])))
|
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) {
|
*m = (CartItem) {
|
||||||
.id = GET_INT("id"),
|
.id = GET_INT("id"),
|
||||||
.cart_id = GET_INT("cart_id"),
|
.cart_id = GET_INT("cart_id"),
|
||||||
|
.product_id = GET_INT("product_id"),
|
||||||
.amount = GET_INT("amount"),
|
.amount = GET_INT("amount"),
|
||||||
};
|
};
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -39,6 +39,7 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
int64_t id;
|
int64_t id;
|
||||||
int64_t cart_id;
|
int64_t cart_id;
|
||||||
|
int64_t product_id;
|
||||||
int64_t amount;
|
int64_t amount;
|
||||||
} CartItem;
|
} CartItem;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user