This commit is contained in:
seb
2026-07-13 07:34:17 +02:00
parent d471f2411d
commit b7b76c9d39
46 changed files with 39025 additions and 7 deletions

View File

@@ -0,0 +1,11 @@
#include "../http.hpp"
#include "../tls_server.hpp"
#include "../router.hpp"
#include "../queries/category_list.hpp"
void handle_category(HttpRequest& req, HttpResponse& resp, RouteContext& ctx) {
int64_t cursor = std::stoll(req.get_query_param("lastChangedCategory", "0"));
int limit = std::stoi(req.get_query_param("limit", "20"));
auto categories = get_category_list(cursor, limit);
resp.send_json(200, categories);
}

View File

@@ -0,0 +1,22 @@
#include "../http.hpp"
#include "../tls_server.hpp"
#include "../router.hpp"
#include "../log.hpp"
#include "../queries/image.hpp"
void handle_cimage(HttpRequest& req, HttpResponse& resp, RouteContext& ctx) {
std::string path = req.get_query_param("path");
if (path.empty()) {
resp.send_json(400, {{"Message", "Missing required query parameter 'path'."}});
return;
}
std::string size = req.get_query_param("size", "200");
ImageResult image = get_image_by_hash(path, size);
if (image.buffer.empty()) {
resp.send_json(404, {{"Message", "No image was found for path '" + path + "'."}});
return;
}
resp.send_binary(200, image.buffer, image.content_type);
}

View File

@@ -0,0 +1,61 @@
// GET /v1/client — pairing handshake (no DB)
// Port of src/endpoints/client.js
#include "../http.hpp"
#include "../pairing.hpp"
#include "../tls_server.hpp"
#include "../router.hpp"
static json build_client_step1(const json& config) {
return {
{"authCode", nullptr},
{"authToken", config["authToken"]},
{"certificateFingerprint", config["certificateFingerprint"]},
{"certificateSerialNumber", config["certificateSerialNumber"]},
{"mandantId", config["mandantId"]},
{"mandantName", nullptr},
{"mandantDatabase", nullptr},
{"serverFingerprint", config["serverFingerprint"]},
{"name", nullptr},
{"serverTimestamp", server_timestamp()},
};
}
static json build_client_step2(const std::string& auth_code, const json& config) {
return {
{"authCode", auth_code},
{"authToken", config["authToken"]},
{"certificateFingerprint", config["certificateFingerprint"]},
{"certificateSerialNumber", config["certificateSerialNumber"]},
{"mandantId", config["mandantId"]},
{"mandantName", config["mandantName"]},
{"mandantDatabase", config["mandantDatabase"]},
{"serverFingerprint", nullptr},
{"name", nullptr},
{"serverTimestamp", server_timestamp()},
};
}
void handle_client(HttpRequest& req, HttpResponse& resp, RouteContext& ctx) {
std::string auth_code = req.get_query_param("authCode");
std::string name = req.get_query_param("name", "JTL-POS");
if (auth_code.size() <= 4 && !auth_code.empty()) {
return resp.send_json(200, build_client_step1(ctx.config));
}
if (auth_code.size() == 6) {
if (ctx.pairing_store->has_pairing_code(auth_code)) {
ctx.pairing_store->revoke_pairing_code(auth_code);
ctx.pairing_store->register_device(ctx.config["authToken"].get<std::string>(), name);
return resp.send_json(200, build_client_step2(auth_code, ctx.config));
}
return resp.send_json(400, {
{"Message", "Der Authentifizierungscode ist falsch."}
});
}
return resp.send_json(400, {
{"Message", "Keinen passenden Authentifizierungscode gefunden."}
});
}

View File

@@ -0,0 +1,10 @@
#include "../http.hpp"
#include "../tls_server.hpp"
#include "../router.hpp"
#include "../queries/customer_groups.hpp"
void handle_customergroup(HttpRequest& req, HttpResponse& resp, RouteContext& ctx) {
int64_t cursor = std::stoll(req.get_query_param("lastChangedCustomerGroup", "0"));
auto groups = get_customer_group_list(cursor);
resp.send_json(200, groups);
}

View File

@@ -0,0 +1,11 @@
#include "../http.hpp"
#include "../tls_server.hpp"
#include "../router.hpp"
#include "../queries/deleted_entity_list.hpp"
void handle_deleted_entity(HttpRequest& req, HttpResponse& resp, RouteContext& ctx) {
int64_t cursor = std::stoll(req.get_query_param("lastChangedDeletedEntity", "0"));
int limit = std::stoi(req.get_query_param("limit", "600"));
auto deleted = get_deleted_entity_list(cursor, limit);
resp.send_json(200, deleted);
}

View File

@@ -0,0 +1,41 @@
#include "../http.hpp"
#include "../tls_server.hpp"
#include "../router.hpp"
#include "../queries/counts.hpp"
#include "../queries/customer_groups.hpp"
#include "../queries/shop.hpp"
#include "../config.hpp"
void handle_init(HttpRequest& req, HttpResponse& resp, RouteContext& ctx) {
int64_t product_cursor = std::stoll(req.get_query_param("lastChangedProduct", "0"));
int64_t category_cursor = std::stoll(req.get_query_param("lastChangedCategory", "0"));
int64_t cg_cursor = std::stoll(req.get_query_param("lastChangedCustomerGroup", "0"));
int64_t composite_cursor = std::stoll(req.get_query_param("lastChangedCompositeProduct", "0"));
int64_t deleted_cursor = std::stoll(req.get_query_param("lastChangedDeletedEntity", "0"));
int root = config::get_int("ROOT_CATEGORY_ID", 1);
int shop = get_active_shop_id();
int64_t product_count = 0, category_count = 0, cg_count = 0, composite_count = 0, deleted_count = 0;
if (get_pool().execute_scalar("SELECT 1") != 0) {
product_count = get_product_count(root, shop, product_cursor);
category_count = get_category_count(root, shop, category_cursor);
cg_count = get_customer_group_count(cg_cursor);
composite_count = get_composite_count(shop, composite_cursor);
deleted_count = get_deleted_count(deleted_cursor);
}
resp.send_json(200, {
{"version", "1.10.12.0"},
{"product_count", std::to_string(product_count)},
{"category_count", std::to_string(category_count)},
{"customer_count", "0"},
{"customerGroup_count", std::to_string(cg_count)},
{"compositeProduct_count", std::to_string(composite_count)},
{"configurationGroup_count", "0"},
{"configurationItem_count", "0"},
{"deletedEntity_count", std::to_string(deleted_count)},
{"max_orderId_count", "0"}
});
}

View File

@@ -0,0 +1,28 @@
#include "../http.hpp"
#include "../tls_server.hpp"
#include "../router.hpp"
#include "../log.hpp"
void handle_order(HttpRequest& req, HttpResponse& resp, RouteContext& ctx) {
// TODO: full order creation (Milestone 5/6)
// For now, parse the JSON body and acknowledge
nlohmann::json body;
try {
body = nlohmann::json::parse(req.body);
} catch (...) {
return resp.send_json(500, nlohmann::json::array());
}
nlohmann::json results = nlohmann::json::array();
if (body.contains("orders") && body["orders"].is_array()) {
for (auto& order : body["orders"]) {
std::string ext_id = order.value("externalId", "");
results.push_back({
{"status", "OK"},
{"externalOrderId", ext_id},
{"message", ""}
});
}
}
resp.send_json(200, results);
}

View File

@@ -0,0 +1,22 @@
#include "../http.hpp"
#include "../tls_server.hpp"
#include "../router.hpp"
#include "../log.hpp"
#include "../queries/image.hpp"
void handle_pimage(HttpRequest& req, HttpResponse& resp, RouteContext& ctx) {
std::string path = req.get_query_param("path");
if (path.empty()) {
resp.send_json(400, {{"Message", "Missing required query parameter 'path'."}});
return;
}
std::string size = req.get_query_param("size", "200");
ImageResult image = get_image_by_hash(path, size);
if (image.buffer.empty()) {
resp.send_json(404, {{"Message", "No image was found for path '" + path + "'."}});
return;
}
resp.send_binary(200, image.buffer, image.content_type);
}

View File

@@ -0,0 +1,11 @@
#include "../http.hpp"
#include "../tls_server.hpp"
#include "../router.hpp"
#include "../queries/product_list.hpp"
void handle_product(HttpRequest& req, HttpResponse& resp, RouteContext& ctx) {
int64_t cursor = std::stoll(req.get_query_param("lastChangedProduct", "0"));
int limit = std::stoi(req.get_query_param("limit", "20"));
auto products = get_product_list(cursor, limit);
resp.send_json(200, products);
}

View File

@@ -0,0 +1,11 @@
#include "../http.hpp"
#include "../tls_server.hpp"
#include "../router.hpp"
#include "../queries/composite_product_list.hpp"
void handle_productcomposite(HttpRequest& req, HttpResponse& resp, RouteContext& ctx) {
int64_t cursor = std::stoll(req.get_query_param("lastChangedCompositeProduct", "0"));
int limit = std::stoi(req.get_query_param("limit", "100"));
auto composites = get_composite_product_list(cursor, limit);
resp.send_json(200, composites);
}