mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-28 08:44:06 +02:00
get one receipt
This commit is contained in:
parent
f799db5b32
commit
2d74a872fe
@ -45,14 +45,17 @@ void route_post_sessions_login(HttpCtx* ctx);
|
|||||||
void route_post_sessions_logout(HttpCtx* ctx);
|
void route_post_sessions_logout(HttpCtx* ctx);
|
||||||
void route_get_sessions_user(HttpCtx* ctx);
|
void route_get_sessions_user(HttpCtx* ctx);
|
||||||
|
|
||||||
|
void route_get_receipt(HttpCtx* ctx);
|
||||||
|
|
||||||
const Session* header_session(HttpCtx* ctx);
|
const Session* header_session(HttpCtx* ctx);
|
||||||
const Session* middleware_session(HttpCtx* ctx);
|
const Session* middleware_session(HttpCtx* ctx);
|
||||||
|
|
||||||
#define RESPOND(HTTP_CTX, STATUS, MIME_TYPE, ...) \
|
#define RESPOND(HTTP_CTX, STATUS, MIME_TYPE, ...) \
|
||||||
{ \
|
{ \
|
||||||
HttpCtx* _ctx = (HTTP_CTX); \
|
HttpCtx* _ctx = (HTTP_CTX); \
|
||||||
char _body[8192]; \
|
size_t _body_size = (size_t)snprintf(NULL, 0, __VA_ARGS__); \
|
||||||
snprintf(_body, 8192 - 1, __VA_ARGS__); \
|
char* _body = calloc(_body_size + 1, sizeof(char)); \
|
||||||
|
sprintf(_body, __VA_ARGS__); \
|
||||||
\
|
\
|
||||||
char content_length[24] = { 0 }; \
|
char content_length[24] = { 0 }; \
|
||||||
snprintf(content_length, 24 - 1, "%ld", strlen(_body)); \
|
snprintf(content_length, 24 - 1, "%ld", strlen(_body)); \
|
||||||
@ -61,6 +64,7 @@ const Session* middleware_session(HttpCtx* ctx);
|
|||||||
http_ctx_res_headers_set(_ctx, "Content-Length", content_length); \
|
http_ctx_res_headers_set(_ctx, "Content-Length", content_length); \
|
||||||
\
|
\
|
||||||
http_ctx_respond(_ctx, (STATUS), _body); \
|
http_ctx_respond(_ctx, (STATUS), _body); \
|
||||||
|
free(_body); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RESPOND_HTML(HTTP_CTX, STATUS, ...) \
|
#define RESPOND_HTML(HTTP_CTX, STATUS, ...) \
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "../http/http.h"
|
#include "../http/http.h"
|
||||||
#include "../models/models_json.h"
|
#include "../models/models_json.h"
|
||||||
#include "controllers.h"
|
#include "controllers.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
void route_get_index(HttpCtx* ctx)
|
void route_get_index(HttpCtx* ctx)
|
||||||
{
|
{
|
||||||
@ -40,6 +41,16 @@ l0_return:
|
|||||||
|
|
||||||
void route_get_not_found(HttpCtx* ctx)
|
void route_get_not_found(HttpCtx* ctx)
|
||||||
{
|
{
|
||||||
|
if (http_ctx_req_headers_has(ctx, "Accept")) {
|
||||||
|
const char* accept = http_ctx_req_headers_get(ctx, "Accept");
|
||||||
|
if (strcmp(accept, "application/json") == 0) {
|
||||||
|
RESPOND_JSON(ctx,
|
||||||
|
404,
|
||||||
|
"{\"ok\":false,\"msg\":\"404 Not Found\",\"path\":\"%s\"}",
|
||||||
|
http_ctx_req_path(ctx));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
RESPOND_HTML(ctx,
|
RESPOND_HTML(ctx,
|
||||||
404,
|
404,
|
||||||
"<!DOCTYPE html><html><head><meta "
|
"<!DOCTYPE html><html><head><meta "
|
||||||
|
107
backend/src/controllers/receipts.c
Normal file
107
backend/src/controllers/receipts.c
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#include "../models/models_json.h"
|
||||||
|
#include "../util/str.h"
|
||||||
|
#include "controllers.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
StrSlice key;
|
||||||
|
StrSlice value;
|
||||||
|
} QueryParamEntry;
|
||||||
|
|
||||||
|
DEFINE_VEC(QueryParamEntry, QueryParamVec, query_param_vec)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
QueryParamVec vec;
|
||||||
|
} QueryParams;
|
||||||
|
|
||||||
|
QueryParams parse_query_params(const char* query)
|
||||||
|
{
|
||||||
|
QueryParams result = {
|
||||||
|
.vec = (QueryParamVec) { 0 },
|
||||||
|
};
|
||||||
|
query_param_vec_construct(&result.vec);
|
||||||
|
|
||||||
|
StrSplitter params = str_splitter(query, strlen(query), "&");
|
||||||
|
StrSlice param;
|
||||||
|
while ((param = str_split_next(¶ms)).len != 0) {
|
||||||
|
StrSplitter left_right = str_splitter(param.ptr, param.len, "=");
|
||||||
|
StrSlice key = str_split_next(&left_right);
|
||||||
|
StrSlice value = str_split_next(&left_right);
|
||||||
|
|
||||||
|
query_param_vec_push(&result.vec, (QueryParamEntry) { key, value });
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
size_t key_len = strlen(key);
|
||||||
|
for (size_t i = 0; i < query_params->vec.size; ++i) {
|
||||||
|
const QueryParamEntry* entry = &query_params->vec.data[i];
|
||||||
|
if (key_len == entry->key.len && strcmp(key, entry->key.ptr)) {
|
||||||
|
return str_slice_copy(&entry->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void route_get_receipt(HttpCtx* ctx)
|
||||||
|
{
|
||||||
|
Cx* cx = http_ctx_user_ctx(ctx);
|
||||||
|
const Session* session = middleware_session(ctx);
|
||||||
|
if (!session)
|
||||||
|
return;
|
||||||
|
|
||||||
|
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");
|
||||||
|
query_params_destroy(¶ms);
|
||||||
|
if (!receipt_id_str) {
|
||||||
|
RESPOND_BAD_REQUEST(ctx, "no receipt_id parameter");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t receipt_id = strtol(receipt_id_str, NULL, 10);
|
||||||
|
|
||||||
|
Receipt receipt;
|
||||||
|
DbRes db_rizz = db_receipt_with_id(cx->db, &receipt, receipt_id);
|
||||||
|
if (db_rizz != DbRes_Ok) {
|
||||||
|
RESPOND_BAD_REQUEST(ctx, "receipt not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProductPriceVec product_prices = { 0 };
|
||||||
|
product_price_vec_construct(&product_prices);
|
||||||
|
db_receipt_prices(cx->db, &product_prices, receipt_id);
|
||||||
|
|
||||||
|
String res;
|
||||||
|
string_construct(&res);
|
||||||
|
|
||||||
|
char* receipt_str = receipt_to_json_string(&receipt);
|
||||||
|
|
||||||
|
string_pushf(
|
||||||
|
&res, "{\"ok\":true,\"receipt\":%s,\"product_prices\":[", receipt_str);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < product_prices.size; ++i) {
|
||||||
|
if (i != 0) {
|
||||||
|
string_pushf(&res, ",");
|
||||||
|
}
|
||||||
|
char* product_price_str
|
||||||
|
= product_price_to_json_string(&product_prices.data[i]);
|
||||||
|
string_pushf(&res, "%s", product_price_str);
|
||||||
|
free(product_price_str);
|
||||||
|
}
|
||||||
|
string_pushf(&res, "]}");
|
||||||
|
|
||||||
|
RESPOND_JSON(ctx, 200, "%s", res.data);
|
||||||
|
string_destroy(&res);
|
||||||
|
product_price_vec_destroy(&product_prices);
|
||||||
|
receipt_destroy(&receipt);
|
||||||
|
}
|
@ -37,3 +37,11 @@ DbRes db_product_price_of_product(
|
|||||||
/// are ignored.
|
/// are ignored.
|
||||||
/// `id` is an out parameter.
|
/// `id` is an out parameter.
|
||||||
DbRes db_receipt_insert(Db* db, const Receipt* receipt, int64_t* id);
|
DbRes db_receipt_insert(Db* db, const Receipt* receipt, int64_t* id);
|
||||||
|
|
||||||
|
/// `receipt` field is an out parameter.
|
||||||
|
DbRes db_receipt_with_id(Db* db, Receipt* receipt, int64_t id);
|
||||||
|
|
||||||
|
/// `product_prices` field is an out parameter.
|
||||||
|
/// Expects `product_prices` to be constructed.
|
||||||
|
DbRes db_receipt_prices(
|
||||||
|
Db* db, ProductPriceVec* product_prices, int64_t receipt_id);
|
||||||
|
@ -373,7 +373,6 @@ DbRes db_product_price_of_product(
|
|||||||
goto l0_return;
|
goto l0_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// find maybe existing product price
|
|
||||||
prepare_res = sqlite3_prepare_v2(connection,
|
prepare_res = sqlite3_prepare_v2(connection,
|
||||||
"SELECT id FROM product_prices"
|
"SELECT id FROM product_prices"
|
||||||
" WHERE product = ? AND price_dkk_cent = ?",
|
" WHERE product = ? AND price_dkk_cent = ?",
|
||||||
@ -484,3 +483,132 @@ l0_return:
|
|||||||
DISCONNECT;
|
DISCONNECT;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DbRes db_receipt_with_id(Db* db, Receipt* receipt, int64_t id)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(Receipt) == 48, "model has changed");
|
||||||
|
|
||||||
|
sqlite3* connection;
|
||||||
|
CONNECT;
|
||||||
|
DbRes res;
|
||||||
|
sqlite3_stmt* stmt = NULL;
|
||||||
|
|
||||||
|
int prepare_res = sqlite3_prepare_v2(connection,
|
||||||
|
"SELECT id, user, datetime(datetime) FROM receipts 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);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
*receipt = (Receipt) {
|
||||||
|
.id = GET_INT(0),
|
||||||
|
.user_id = GET_INT(1),
|
||||||
|
.timestamp = GET_STR(2),
|
||||||
|
.products = (ReceiptProductVec) { 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
receipt_product_vec_construct(&receipt->products);
|
||||||
|
|
||||||
|
prepare_res = sqlite3_prepare_v2(connection,
|
||||||
|
"SELECT id, receipt, product_price, amount FROM receipt_products"
|
||||||
|
" WHERE receipt = ?",
|
||||||
|
-1,
|
||||||
|
&stmt,
|
||||||
|
NULL);
|
||||||
|
if (prepare_res != SQLITE_OK) {
|
||||||
|
REPORT_SQLITE3_ERROR();
|
||||||
|
res = DbRes_Error;
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
sqlite3_bind_int64(stmt, 1, receipt->id);
|
||||||
|
|
||||||
|
int sqlite_res;
|
||||||
|
while ((sqlite_res = sqlite3_step(stmt)) == SQLITE_ROW) {
|
||||||
|
ReceiptProduct product = {
|
||||||
|
.id = GET_INT(0),
|
||||||
|
.receipt_id = GET_INT(1),
|
||||||
|
.product_price_id = GET_INT(2),
|
||||||
|
.amount = GET_INT(3),
|
||||||
|
};
|
||||||
|
receipt_product_vec_push(&receipt->products, product);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
DbRes db_receipt_prices(
|
||||||
|
Db* db, ProductPriceVec* product_prices, int64_t receipt_id)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(ProductPrice) == 24, "model has changed");
|
||||||
|
|
||||||
|
sqlite3* connection;
|
||||||
|
CONNECT;
|
||||||
|
DbRes res;
|
||||||
|
sqlite3_stmt* stmt = NULL;
|
||||||
|
|
||||||
|
int prepare_res = sqlite3_prepare_v2(connection,
|
||||||
|
"SELECT product_prices.id, product_prices.product,"
|
||||||
|
" product_prices.price_dkk_cent"
|
||||||
|
" FROM receipt_products JOIN product_prices"
|
||||||
|
" ON product_prices.id = product_price"
|
||||||
|
" AND receipt_products.receipt = ?",
|
||||||
|
-1,
|
||||||
|
&stmt,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (prepare_res != SQLITE_OK) {
|
||||||
|
REPORT_SQLITE3_ERROR();
|
||||||
|
res = DbRes_Error;
|
||||||
|
goto l0_return;
|
||||||
|
}
|
||||||
|
sqlite3_bind_int64(stmt, 1, receipt_id);
|
||||||
|
|
||||||
|
int sqlite_res;
|
||||||
|
while ((sqlite_res = sqlite3_step(stmt)) == SQLITE_ROW) {
|
||||||
|
ProductPrice product_price = {
|
||||||
|
.id = GET_INT(0),
|
||||||
|
.product_id = GET_INT(1),
|
||||||
|
.price_dkk_cent = GET_INT(2),
|
||||||
|
};
|
||||||
|
product_price_vec_push(product_prices, product_price);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
@ -143,12 +143,12 @@ static inline int parse_request_header(Client* client, Request* request)
|
|||||||
char* query = NULL;
|
char* query = NULL;
|
||||||
if (path_len < uri_str.len) {
|
if (path_len < uri_str.len) {
|
||||||
size_t query_len = 0;
|
size_t query_len = 0;
|
||||||
while (path_len + query_len < uri_str.len
|
while (path_len + query_len + 1 < uri_str.len
|
||||||
&& uri_str.ptr[path_len + query_len] != '#') {
|
&& uri_str.ptr[path_len + query_len] != '#') {
|
||||||
query_len += 1;
|
query_len += 1;
|
||||||
}
|
}
|
||||||
query = calloc(query_len + 1, sizeof(char));
|
query = calloc(query_len + 1, sizeof(char));
|
||||||
strncpy(query, &uri_str.ptr[path_len], query_len);
|
strncpy(query, &uri_str.ptr[path_len + 1], query_len);
|
||||||
query[query_len] = '\0';
|
query[query_len] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ void* http_ctx_user_ctx(HttpCtx* ctx);
|
|||||||
const char* http_ctx_req_path(HttpCtx* ctx);
|
const char* http_ctx_req_path(HttpCtx* ctx);
|
||||||
bool http_ctx_req_headers_has(HttpCtx* ctx, const char* key);
|
bool http_ctx_req_headers_has(HttpCtx* ctx, const char* key);
|
||||||
const char* http_ctx_req_headers_get(HttpCtx* ctx, const char* key);
|
const char* http_ctx_req_headers_get(HttpCtx* ctx, const char* key);
|
||||||
|
const char* http_ctx_req_query(HttpCtx* ctx);
|
||||||
const char* http_ctx_req_body(HttpCtx* ctx);
|
const char* http_ctx_req_body(HttpCtx* ctx);
|
||||||
void http_ctx_res_headers_set(HttpCtx* ctx, const char* key, const char* value);
|
void http_ctx_res_headers_set(HttpCtx* ctx, const char* key, const char* value);
|
||||||
void http_ctx_respond(HttpCtx* ctx, int status, const char* body);
|
void http_ctx_respond(HttpCtx* ctx, int status, const char* body);
|
||||||
|
@ -155,6 +155,11 @@ const char* http_ctx_req_headers_get(HttpCtx* ctx, const char* key)
|
|||||||
return http_request_get_header(ctx->req, key);
|
return http_request_get_header(ctx->req, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* http_ctx_req_query(HttpCtx* ctx)
|
||||||
|
{
|
||||||
|
return ctx->req->query;
|
||||||
|
}
|
||||||
|
|
||||||
const char* http_ctx_req_body(HttpCtx* ctx)
|
const char* http_ctx_req_body(HttpCtx* ctx)
|
||||||
{
|
{
|
||||||
return ctx->req_body;
|
return ctx->req_body;
|
||||||
|
@ -41,6 +41,8 @@ int main(void)
|
|||||||
|
|
||||||
http_server_post(server, "/api/carts/purchase", route_post_carts_purchase);
|
http_server_post(server, "/api/carts/purchase", route_post_carts_purchase);
|
||||||
|
|
||||||
|
http_server_get(server, "/api/receipts/one", route_get_receipt);
|
||||||
|
|
||||||
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(
|
||||||
|
@ -14,6 +14,14 @@ char* str_dup(const char* str)
|
|||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* str_slice_copy(const StrSlice* slice)
|
||||||
|
{
|
||||||
|
char* copy = malloc(slice->len + 1);
|
||||||
|
strncpy(copy, slice->ptr, slice->len);
|
||||||
|
copy[slice->len] = '\0';
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
StrSplitter str_splitter(const char* text, size_t text_len, const char* split)
|
StrSplitter str_splitter(const char* text, size_t text_len, const char* split)
|
||||||
{
|
{
|
||||||
return (StrSplitter) {
|
return (StrSplitter) {
|
||||||
@ -36,10 +44,12 @@ StrSlice str_split_next(StrSplitter* splitter)
|
|||||||
return (StrSlice) { ptr, len };
|
return (StrSlice) { ptr, len };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (StrSlice) {
|
StrSlice slice = {
|
||||||
.ptr = &splitter->text[splitter->i],
|
.ptr = &splitter->text[splitter->i],
|
||||||
.len = splitter->text_len - splitter->i,
|
.len = splitter->text_len - splitter->i,
|
||||||
};
|
};
|
||||||
|
splitter->i = splitter->text_len;
|
||||||
|
return slice;
|
||||||
}
|
}
|
||||||
|
|
||||||
void string_push_str(String* string, const char* str)
|
void string_push_str(String* string, const char* str)
|
||||||
|
@ -12,6 +12,8 @@ typedef struct {
|
|||||||
size_t len;
|
size_t len;
|
||||||
} StrSlice;
|
} StrSlice;
|
||||||
|
|
||||||
|
const char* str_slice_copy(const StrSlice* slice);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char* text;
|
const char* text;
|
||||||
size_t text_len;
|
size_t text_len;
|
||||||
|
@ -49,7 +49,7 @@ Deno.test("test backend", async (t) => {
|
|||||||
// console.log(sessionUserRes.user);
|
// console.log(sessionUserRes.user);
|
||||||
});
|
});
|
||||||
|
|
||||||
await testCarts(t, token);
|
await testCartsAndReceipts(t, token);
|
||||||
|
|
||||||
await t.step("test /api/sessions/logout", async () => {
|
await t.step("test /api/sessions/logout", async () => {
|
||||||
const logoutRes = await post<{ ok: boolean }>(
|
const logoutRes = await post<{ ok: boolean }>(
|
||||||
@ -62,9 +62,11 @@ Deno.test("test backend", async (t) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
async function testCarts(t: Deno.TestContext, token: string) {
|
async function testCartsAndReceipts(t: Deno.TestContext, token: string) {
|
||||||
|
let receiptId: number | undefined = undefined;
|
||||||
|
|
||||||
await t.step("test /api/carts/purchase", async () => {
|
await t.step("test /api/carts/purchase", async () => {
|
||||||
const res = await post<{ ok: boolean }>(
|
const res = await post<{ ok: boolean; receipt_id: number }>(
|
||||||
"/api/carts/purchase",
|
"/api/carts/purchase",
|
||||||
{
|
{
|
||||||
items: [
|
items: [
|
||||||
@ -76,6 +78,21 @@ async function testCarts(t: Deno.TestContext, token: string) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assertEquals(res.ok, true);
|
assertEquals(res.ok, true);
|
||||||
|
receiptId = res.receipt_id;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!receiptId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await t.step("test /api/receipts/one", async () => {
|
||||||
|
const res = await get<{ ok: boolean }>(
|
||||||
|
`/api/receipts/one?receipt_id=${receiptId}`,
|
||||||
|
{ "Session-Token": token },
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(res);
|
||||||
|
assertEquals(res.ok, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +100,9 @@ function get<Res>(
|
|||||||
path: string,
|
path: string,
|
||||||
headers: Record<string, string>,
|
headers: Record<string, string>,
|
||||||
): Promise<Res> {
|
): Promise<Res> {
|
||||||
return fetch(`${url}${path}`, { headers })
|
return fetch(`${url}${path}`, {
|
||||||
|
headers: { ...headers, "Accept": "application/json" },
|
||||||
|
})
|
||||||
.then((res) => res.json());
|
.then((res) => res.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +113,11 @@ function post<Res, Req = unknown>(
|
|||||||
): Promise<Res> {
|
): Promise<Res> {
|
||||||
return fetch(`${url}${path}`, {
|
return fetch(`${url}${path}`, {
|
||||||
method: "post",
|
method: "post",
|
||||||
headers: { ...headers, "Content-Type": "application/json" },
|
headers: {
|
||||||
|
...headers,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept": "application/json",
|
||||||
|
},
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
}).then((res) => res.json());
|
}).then((res) => res.json());
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user