diff --git a/qml/components/ProductDialog.qml b/qml/components/ProductDialog.qml index ebd9c68..374eab5 100644 --- a/qml/components/ProductDialog.qml +++ b/qml/components/ProductDialog.qml @@ -271,6 +271,41 @@ Popup { } } } + + Item { + width: 500; height: childrenRect.height + Text { + anchors.left: parent.left + anchors.verticalCenter: quantityPerOrderField.verticalCenter + text: qsTr("Limit quantity per order") + color: productDialog.palette.text + font.pointSize: 10 + } + TextField { + id: quantityPerOrderField + anchors.right: parent.right + width: 50; height: 25 + placeholderText: qsTr("#") + font.pixelSize: 12 + color: productDialog.inputTextColor + selectByMouse: true + inputMethodHints: Qt.ImhDigitsOnly + validator: RegExpValidator{ regExp: /[0-9]*/ } + onTextChanged: { + if (text.length > 2) text = text.substring(0, 2); + } + onEditingFinished: { + if (text === "00") text = ""; + if (text.startsWith("0")) text = text.substring(1); + } + background: Rectangle { + color: "transparent" + border.color: productDialog.inputBorderColor + border.width: parent.activeFocus ? 2 : 1 + radius: productDialog.inputRadius + } + } + } } } // Product condition @@ -965,7 +1000,8 @@ Popup { productPriceField.text, selectedCurrencyText.text, productConditionBox.currentText, - productLocationBox.currentText + productLocationBox.currentText, + (quantityPerOrderField.text.length > 0) ? Number(quantityPerOrderField.text) : 0 ) // Save product thumbnail Backend.saveProductThumbnail(productImages[0].source, listing_key) @@ -985,6 +1021,7 @@ Popup { productLocationBox.currentIndex = productLocationBox.find("Unspecified")//find("Worldwide") productDescriptionEdit.text = "" productTagsField.clearTags() + quantityPerOrderField.text = "" // Clear upload images as well for(let i = 0; i < productImageRepeater.count; i++) { let productImage = productImageRepeater.itemAt(i).children[0].children[0] diff --git a/src/core/listing.cpp b/src/core/listing.cpp index 6388ffa..e1a0fc1 100644 --- a/src/core/listing.cpp +++ b/src/core/listing.cpp @@ -4,25 +4,29 @@ #include "product.hpp" -neroshop::Listing::Listing() : quantity(0), price(0.00) {} +neroshop::Listing::Listing() : quantity(0), price(0.00), quantity_per_order(0) {} neroshop::Listing::Listing(const std::string& id, const Product& product, const std::string& seller_id, unsigned int quantity, - double price, const std::string& currency, const std::string& condition, const std::string& location, const std::string& date, const std::string& signature) + double price, const std::string& currency, const std::string& condition, const std::string& location, const std::string& date, const std::string& signature, + unsigned int quantity_per_order) : id(id), product(std::make_unique(product)), seller_id(seller_id), quantity(quantity), - price(price), currency(currency), condition(condition), location(location), date(date), signature(signature) + price(price), currency(currency), condition(condition), location(location), date(date), signature(signature), + quantity_per_order(quantity_per_order) {} neroshop::Listing::Listing(const Listing& other) : id(other.id), product(std::make_unique(*other.product)), seller_id(other.seller_id), quantity(other.quantity), price(other.price), currency(other.currency), condition(other.condition), location(other.location), - date(other.date), signature(other.signature) + date(other.date), signature(other.signature), + quantity_per_order(other.quantity_per_order) {} neroshop::Listing::Listing(Listing&& other) noexcept : id(std::move(other.id)), product(std::move(other.product)), seller_id(std::move(other.seller_id)), quantity(std::exchange(other.quantity, 0)), price(std::exchange(other.price, 0.0)), currency(std::move(other.currency)), condition(std::move(other.condition)), location(std::move(other.location)), - date(std::move(other.date)), signature(std::move(other.signature)) + date(std::move(other.date)), signature(std::move(other.signature)), + quantity_per_order(std::exchange(other.quantity_per_order, 0)) {} //----------------------------------------------------------------------------- @@ -40,6 +44,7 @@ neroshop::Listing& neroshop::Listing::operator=(const neroshop::Listing& other) location = other.location; date = other.date; signature = other.signature; + quantity_per_order = other.quantity_per_order; } return *this; } @@ -57,6 +62,7 @@ neroshop::Listing& neroshop::Listing::operator=(neroshop::Listing&& other) noexc location = std::move(other.location); date = std::move(other.date); signature = std::move(other.signature); + quantity_per_order = std::exchange(other.quantity_per_order, 0); } return *this; } @@ -133,6 +139,10 @@ void neroshop::Listing::set_signature(const std::string& signature) { this->signature = signature; } +void neroshop::Listing::set_quantity_per_order(unsigned int quantity_per_order) { + this->quantity_per_order = quantity_per_order; +} + //----------------------------------------------------------------------------- std::string neroshop::Listing::get_id() const { @@ -181,3 +191,7 @@ neroshop::Product * neroshop::Listing::get_product() const { std::string neroshop::Listing::get_signature() const { return signature; } + +int neroshop::Listing::get_quantity_per_order() const { + return quantity_per_order; +} diff --git a/src/core/listing.hpp b/src/core/listing.hpp index 9dd6128..886005d 100644 --- a/src/core/listing.hpp +++ b/src/core/listing.hpp @@ -12,7 +12,8 @@ class Listing { public: Listing(); Listing(const std::string& id, const Product& product, const std::string& seller_id, unsigned int quantity, - double price, const std::string& currency, const std::string& condition, const std::string& location, const std::string& date, const std::string& signature); + double price, const std::string& currency, const std::string& condition, const std::string& location, const std::string& date, const std::string& signature, + unsigned int quantity_per_order); Listing(const Listing& other);// copy constructor Listing(Listing&& other) noexcept; // move constructor @@ -32,6 +33,7 @@ public: void set_date(const std::string& date); void set_product(const Product& product); void set_signature(const std::string& signature); + void set_quantity_per_order(unsigned int quantity_per_order); std::string get_id() const; std::string get_product_id() const; @@ -44,6 +46,7 @@ public: std::string get_date() const; Product * get_product() const; std::string get_signature() const; + int get_quantity_per_order() const; private: std::string id; std::string seller_id; @@ -55,6 +58,7 @@ private: std::string date; // date the listing was `created_at` std::string signature; std::unique_ptr product; + unsigned int quantity_per_order; }; } diff --git a/src/core/protocol/p2p/serializer.cpp b/src/core/protocol/p2p/serializer.cpp index 0916207..c1bcaa1 100644 --- a/src/core/protocol/p2p/serializer.cpp +++ b/src/core/protocol/p2p/serializer.cpp @@ -58,6 +58,10 @@ std::pair*/> neroshop::Serializer } json_object["date"] = listing.get_date(); json_object["signature"] = listing.get_signature();// listings can be updated by the user that can verify the signature + int quantity_per_order = listing.get_quantity_per_order(); + if(quantity_per_order > 0) { + json_object["quantity_per_order"] = quantity_per_order; + } json_object["metadata"] = "listing"; // Include the product serialization within the listing serialization assert(listing.get_product() != nullptr); diff --git a/src/core/seller.cpp b/src/core/seller.cpp index a6fa95e..0d1eeba 100644 --- a/src/core/seller.cpp +++ b/src/core/seller.cpp @@ -56,7 +56,8 @@ std::string neroshop::Seller::list_item( double price, const std::string& currency, const std::string& condition, - const std::string& location + const std::string& location, + unsigned int quantity_per_order ) const { // Transition from Sqlite to DHT: @@ -84,7 +85,7 @@ std::string neroshop::Seller::list_item( Listing listing { listing_id, product, seller_id, quantity, price, currency, - condition, location, created_at, signature + condition, location, created_at, signature, quantity_per_order };//listing.print_listing(); auto data = Serializer::serialize(listing); diff --git a/src/core/seller.hpp b/src/core/seller.hpp index ab3e0d1..c9b35ed 100644 --- a/src/core/seller.hpp +++ b/src/core/seller.hpp @@ -37,7 +37,8 @@ public: const std::string& currency, /*double discount = 0.00, unsigned int discounted_items = 1, unsigned int discount_times = 1, std::string discount_expiry = "0000-00-00 00:00:00", */ const std::string& condition, - const std::string& location + const std::string& location, + unsigned int quantity_per_order ) const; // adds an item to the inventory ////void list_item(const neroshop::Product& item, unsigned int stock_qty, double sales_price = 0.00, std::string currency = "usd", double discount = 0.00, unsigned int discounted_items = 1, unsigned int discount_times = 1, std::string discount_expiry = ""/*"0000-00-00 00:00:00"*/, std::string condition = "new"); void delist_item(const std::string& listing_key); // deletes an item from the inventory diff --git a/src/gui/backend.cpp b/src/gui/backend.cpp index df254b3..cb152e6 100644 --- a/src/gui/backend.cpp +++ b/src/gui/backend.cpp @@ -1073,6 +1073,9 @@ QVariantList neroshop::Backend::getListingsBySearchTerm(const QString& searchTer listing.insert("location", QString::fromStdString(value_obj["location"].get())); } listing.insert("date", QString::fromStdString(value_obj["date"].get())); + if(value_obj.contains("quantity_per_order") && value_obj["quantity_per_order"].is_number_integer()) { + listing.insert("quantity_per_order", value_obj["quantity_per_order"].get()); + } assert(value_obj["product"].is_object()); const auto& product_obj = value_obj["product"]; ////listing.insert("product_uuid", QString::fromStdString(product_obj["id"].get())); @@ -1187,6 +1190,9 @@ QVariantList neroshop::Backend::getListings(int sorting, bool hide_illicit_items listing.insert("location", QString::fromStdString(value_obj["location"].get())); } listing.insert("date", QString::fromStdString(value_obj["date"].get())); + if(value_obj.contains("quantity_per_order") && value_obj["quantity_per_order"].is_number_integer()) { + listing.insert("quantity_per_order", value_obj["quantity_per_order"].get()); + } assert(value_obj["product"].is_object()); const auto& product_obj = value_obj["product"]; ////listing.insert("product_uuid", QString::fromStdString(product_obj["id"].get())); @@ -1407,6 +1413,9 @@ QVariantList neroshop::Backend::getListingsByCategory(int category_id, bool hide listing.insert("location", QString::fromStdString(value_obj["location"].get())); } listing.insert("date", QString::fromStdString(value_obj["date"].get())); + if(value_obj.contains("quantity_per_order") && value_obj["quantity_per_order"].is_number_integer()) { + listing.insert("quantity_per_order", value_obj["quantity_per_order"].get()); + } assert(value_obj["product"].is_object()); const auto& product_obj = value_obj["product"]; ////listing.insert("product_uuid", QString::fromStdString(product_obj["id"].get())); diff --git a/src/gui/user_controller.cpp b/src/gui/user_controller.cpp index dc3c8eb..18cbc92 100644 --- a/src/gui/user_controller.cpp +++ b/src/gui/user_controller.cpp @@ -22,7 +22,7 @@ neroshop::UserController::~UserController() { QString neroshop::UserController::listProduct(const QString& name, const QString& description, const QList& attributes, const QString& product_code, int category_id, const QList& subcategory_ids, const QStringList& tags, const QList& images, -int quantity, double price, const QString& currency, const QString& condition, const QString& location) { +int quantity, double price, const QString& currency, const QString& condition, const QString& location, int quantity_per_order) { if (!_user) throw std::runtime_error("neroshop::User is not initialized"); auto seller = dynamic_cast(_user.get()); @@ -110,7 +110,8 @@ int quantity, double price, const QString& currency, const QString& condition, c price, currency.toStdString(), condition.toStdString(), - location.toStdString() + location.toStdString(), + quantity_per_order ); emit productsCountChanged(); emit inventoryChanged(); diff --git a/src/gui/user_controller.hpp b/src/gui/user_controller.hpp index dc272ef..f12867b 100644 --- a/src/gui/user_controller.hpp +++ b/src/gui/user_controller.hpp @@ -45,7 +45,8 @@ public: double price, const QString& currency, const QString& condition, - const QString& location + const QString& location, + int quantity_per_order ); Q_INVOKABLE void delistProduct(const QString& listing_key); Q_INVOKABLE void delistProducts(const QStringList& listing_keys); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c7fcb43..ab674a6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -423,7 +423,14 @@ include_directories(${neroshop_root}/external/lua/src) # v5.4.4 set(lua_src liblua.a) ###################################### -# +# libi2pd (and i2pd_client) +include_directories(${neroshop_root}/external/i2pd/libi2pd ${neroshop_root}/external/i2pd/libi2pd_client) +set(i2pd_src libi2pd.a libi2pd_client.a) + +###################################### +# i2psam +#[[include_directories(${neroshop_root}/external/i2psam/) +set(i2psam_src libi2psam.a)]] ###################################### # network_test @@ -482,6 +489,10 @@ set(test_wallet "wallet_test") add_executable(${test_wallet} wallet_test.cpp ${neroshop_srcs}) target_link_libraries(${test_wallet} ${monero_cpp_src} ${sqlite_src} ${qr_code_generator_src} ${raft_src} ${curl_src} ${monero_src} ${lua_src}) +#[[set(test_i2pd "i2pd_test") +add_executable(${test_i2pd} i2pd_test.cpp ${neroshop_srcs}) +target_link_libraries(${test_i2pd} ${monero_cpp_src} ${sqlite_src} ${qr_code_generator_src} ${raft_src} ${monero_src} ${lua_src} ${i2pd_src})]] + #[[ set(test_ "") add_executable(${test_} .cpp ${neroshop_srcs}) @@ -510,6 +521,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") target_link_libraries(${test_gui_qt} ${posix_src}) target_link_libraries(${test_escrow} ${posix_src}) target_link_libraries(${test_wallet} ${posix_src}) + #target_link_libraries(${test_i2pd} ${posix_src}) #target_link_libraries(${test_} ${posix_src}) find_package(X11 REQUIRED) if(X11_FOUND) diff --git a/tests/i2pd_test.cpp b/tests/i2pd_test.cpp new file mode 100644 index 0000000..2e559bb --- /dev/null +++ b/tests/i2pd_test.cpp @@ -0,0 +1,18 @@ +#include +#include + +void start_router(int argc, char* argv[]) { + i2p::api::InitI2P(argc, argv, "neromon"); + + // Your application logic + + i2p::api::StartI2P(std::shared_ptr(nullptr)); // Pass a log stream if needed + + // Your application continues running + + i2p::api::StopI2P(); +} + +int main(int argc, char* argv[]) { + return 0; +}