diff --git a/backend/src/controllers/controllers.h b/backend/src/controllers/controllers.h index e5cf5fb..1ef91a2 100644 --- a/backend/src/controllers/controllers.h +++ b/backend/src/controllers/controllers.h @@ -40,12 +40,13 @@ void route_get_products_all(HttpCtx* ctx); void route_post_carts_purchase(HttpCtx* ctx); void route_post_users_register(HttpCtx* ctx); +void route_post_users_balance_add(HttpCtx* ctx); void route_post_sessions_login(HttpCtx* ctx); void route_post_sessions_logout(HttpCtx* ctx); void route_get_sessions_user(HttpCtx* ctx); -void route_get_receipt(HttpCtx* ctx); +void route_get_receipts_one(HttpCtx* ctx); const Session* header_session(HttpCtx* ctx); const Session* middleware_session(HttpCtx* ctx); diff --git a/backend/src/controllers/receipts.c b/backend/src/controllers/receipts.c index ef2326d..17c6414 100644 --- a/backend/src/controllers/receipts.c +++ b/backend/src/controllers/receipts.c @@ -40,7 +40,7 @@ void query_params_destroy(QueryParams* query_params) query_param_vec_destroy(&query_params->vec); } -const char* query_params_get(const QueryParams* query_params, const char* key) +char* query_params_get(const QueryParams* query_params, const char* key) { size_t key_len = strlen(key); for (size_t i = 0; i < query_params->vec.size; ++i) { @@ -52,7 +52,7 @@ const char* query_params_get(const QueryParams* query_params, const char* key) return NULL; } -void route_get_receipt(HttpCtx* ctx) +void route_get_receipts_one(HttpCtx* ctx) { Cx* cx = http_ctx_user_ctx(ctx); const Session* session = middleware_session(ctx); @@ -61,7 +61,7 @@ void route_get_receipt(HttpCtx* ctx) const char* query = http_ctx_req_query(ctx); QueryParams params = parse_query_params(query); - const char* receipt_id_str = query_params_get(¶ms, "receipt_id"); + char* receipt_id_str = query_params_get(¶ms, "receipt_id"); query_params_destroy(¶ms); if (!receipt_id_str) { RESPOND_BAD_REQUEST(ctx, "no receipt_id parameter"); @@ -69,6 +69,7 @@ void route_get_receipt(HttpCtx* ctx) } int64_t receipt_id = strtol(receipt_id_str, NULL, 10); + free(receipt_id_str); Receipt receipt; DbRes db_rizz = db_receipt_with_id(cx->db, &receipt, receipt_id); diff --git a/backend/src/controllers/users.c b/backend/src/controllers/users.c index 377b267..e7b1b39 100644 --- a/backend/src/controllers/users.c +++ b/backend/src/controllers/users.c @@ -61,24 +61,27 @@ void route_post_users_register(HttpCtx* ctx) RESPOND_JSON(ctx, 200, "{\"ok\":true}"); } -void route_add_balance(HttpCtx* ctx) +void route_post_users_balance_add(HttpCtx* ctx) { Cx* cx = http_ctx_user_ctx(ctx); const Session* session = middleware_session(ctx); if (!session) return; - printf("token: %s\n user_id: %ld\n", session->token, session->user_id); - 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"); + User user; + if (db_user_with_id(cx->db, &user, session->user_id) != DbRes_Ok) { + RESPOND_SERVER_ERROR(ctx); return; } - json_free(body_json); + user.balance_dkk_cent += 10000; - + DbRes db_res = db_user_update(cx->db, &user); + user_destroy(&user); + if (db_res != DbRes_Ok) { + RESPOND_SERVER_ERROR(ctx); + return; + } + + RESPOND_JSON(ctx, 200, "{\"ok\":true}"); } - - diff --git a/backend/src/db/db.h b/backend/src/db/db.h index 8dd4193..6032cd8 100644 --- a/backend/src/db/db.h +++ b/backend/src/db/db.h @@ -18,6 +18,10 @@ typedef struct Db Db; /// `user.id` field is ignored. DbRes db_user_insert(Db* db, const User* user); + +/// Uses `user.id` to find model. +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); diff --git a/backend/src/db/db_sqlite.c b/backend/src/db/db_sqlite.c index 13d9f0e..aa11bbc 100644 --- a/backend/src/db/db_sqlite.c +++ b/backend/src/db/db_sqlite.c @@ -48,7 +48,10 @@ void db_sqlite_free(Db* db) static inline DbRes connect(sqlite3** connection) { - int res = sqlite3_open("database.db", connection); + int res = sqlite3_open_v2("database.db", + connection, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_NOMUTEX, + NULL); if (res != SQLITE_OK) { fprintf(stderr, "error: could not open sqlite 'database.db'\n %s\n", @@ -84,18 +87,65 @@ DbRes db_user_insert(Db* db, const User* user) DbRes res; sqlite3_stmt* stmt; - sqlite3_prepare_v2(connection, + int prepare_res = sqlite3_prepare_v2(connection, "INSERT INTO users (name, email, password_hash, balance_dkk_cent) " "VALUES (?, ?, ?, ?)", -1, &stmt, NULL); + if (prepare_res != SQLITE_OK) { + REPORT_SQLITE3_ERROR(); + res = DbRes_Error; + goto l0_return; + } sqlite3_bind_text(stmt, 1, user->name, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, user->email, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 3, user->password_hash, -1, SQLITE_STATIC); sqlite3_bind_int64(stmt, 4, user->balance_dkk_cent); + 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_user_update(Db* db, const User* user) +{ + static_assert(sizeof(User) == 40, "model has changed"); + + sqlite3* connection; + CONNECT; + DbRes res; + + sqlite3_stmt* stmt; + int prepare_res = sqlite3_prepare_v2(connection, + "UPDATE users SET name = ?, email = ?, password_hash= ?, " + "balance_dkk_cent= ? WHERE id = ?", + -1, + &stmt, + NULL); + if (prepare_res != SQLITE_OK) { + REPORT_SQLITE3_ERROR(); + res = DbRes_Error; + goto l0_return; + } + + sqlite3_bind_text(stmt, 1, user->name, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 2, user->email, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 3, user->password_hash, -1, SQLITE_STATIC); + sqlite3_bind_int64(stmt, 4, user->balance_dkk_cent); + sqlite3_bind_int64(stmt, 5, user->id); + int step_res = sqlite3_step(stmt); if (step_res != SQLITE_DONE) { fprintf(stderr, "error: %s\n", sqlite3_errmsg(connection)); @@ -120,12 +170,17 @@ DbRes db_user_with_id(Db* db, User* user, int64_t id) DbRes res; sqlite3_stmt* stmt; - sqlite3_prepare_v2(connection, + int prepare_res = sqlite3_prepare_v2(connection, "SELECT id, name, email, password_hash, balance_dkk_cent" " FROM users WHERE id = ?", -1, &stmt, NULL); + if (prepare_res != SQLITE_OK) { + REPORT_SQLITE3_ERROR(); + res = DbRes_Error; + goto l0_return; + } sqlite3_bind_int64(stmt, 1, id); int step_res = sqlite3_step(stmt); @@ -526,6 +581,7 @@ DbRes db_receipt_with_id(Db* db, Receipt* receipt, int64_t id) receipt_product_vec_construct(&receipt->products); + sqlite3_finalize(stmt); prepare_res = sqlite3_prepare_v2(connection, "SELECT id, receipt, product_price, amount FROM receipt_products" " WHERE receipt = ?", diff --git a/backend/src/main.c b/backend/src/main.c index a9678f7..367de3c 100644 --- a/backend/src/main.c +++ b/backend/src/main.c @@ -41,9 +41,12 @@ int main(void) http_server_post(server, "/api/carts/purchase", route_post_carts_purchase); - http_server_get(server, "/api/receipts/one", route_get_receipt); + http_server_get(server, "/api/receipts/one", route_get_receipts_one); http_server_post(server, "/api/users/register", route_post_users_register); + http_server_post( + server, "/api/users/balance/add", route_post_users_balance_add); + http_server_post(server, "/api/sessions/login", route_post_sessions_login); http_server_post( server, "/api/sessions/logout", route_post_sessions_logout); diff --git a/backend/src/util/str.c b/backend/src/util/str.c index c3fe7cd..e144b03 100644 --- a/backend/src/util/str.c +++ b/backend/src/util/str.c @@ -14,7 +14,7 @@ char* str_dup(const char* str) return clone; } -const char* str_slice_copy(const StrSlice* slice) +char* str_slice_copy(const StrSlice* slice) { char* copy = malloc(slice->len + 1); strncpy(copy, slice->ptr, slice->len); diff --git a/backend/src/util/str.h b/backend/src/util/str.h index 576da7f..8510a29 100644 --- a/backend/src/util/str.h +++ b/backend/src/util/str.h @@ -12,7 +12,7 @@ typedef struct { size_t len; } StrSlice; -const char* str_slice_copy(const StrSlice* slice); +char* str_slice_copy(const StrSlice* slice); typedef struct { const char* text; diff --git a/backend/test/test.ts b/backend/test/test.ts index 742da7d..14edc24 100644 --- a/backend/test/test.ts +++ b/backend/test/test.ts @@ -49,7 +49,18 @@ Deno.test("test backend", async (t) => { // console.log(sessionUserRes.user); }); - await testCartsAndReceipts(t, token); + await t.step("test /api/users/balance/add", async () => { + const sessionUserRes = await post<{ ok: boolean }>( + "/api/users/balance/add", + {}, + { "Session-Token": token! }, + ); + + // console.log(sessionUserRes); + assertEquals(sessionUserRes.ok, true); + }); + + await testCartsAndReceipts(t, token!); await t.step("test /api/sessions/logout", async () => { const logoutRes = await post<{ ok: boolean }>( @@ -91,7 +102,7 @@ async function testCartsAndReceipts(t: Deno.TestContext, token: string) { { "Session-Token": token }, ); - console.log(res); + // console.log(res); assertEquals(res.ok, true); }); }