users balance add

This commit is contained in:
SimonFJ20 2025-03-17 13:44:48 +01:00
parent b811c208c9
commit 974f057dc1
9 changed files with 101 additions and 22 deletions

@ -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);

@ -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(&params, "receipt_id");
char* receipt_id_str = query_params_get(&params, "receipt_id");
query_params_destroy(&params);
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);

@ -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}");
}

@ -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);

@ -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 = ?",

@ -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);

@ -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);

@ -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;

@ -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);
});
}