From 45a3ade1cb3521e0406de28859d3d4ca7a298b00 Mon Sep 17 00:00:00 2001 From: larteyoh Date: Mon, 10 Jul 2023 05:42:17 -0400 Subject: [PATCH] add favorites (wishlist) feature --- qml/components/CatalogGrid.qml | 8 +- qml/components/ProductDialog.qml | 8 +- qml/components/TagField.qml | 2 +- src/core/category.hpp | 38 ++-- src/core/image.hpp | 3 +- src/core/protocol/p2p/serializer.cpp | 2 +- src/core/seller.cpp | 4 +- src/core/tools/base64.cpp | 72 +++++++ src/core/tools/base64.hpp | 4 + src/core/user.cpp | 170 ++++++++-------- src/core/user.hpp | 12 +- src/gui/backend.cpp | 281 +++++++++++++-------------- src/gui/backend.hpp | 9 +- src/gui/user_controller.cpp | 17 ++ src/gui/user_controller.hpp | 6 +- tests/request/request | Bin 29856 -> 29856 bytes tests/request/request.cpp | 2 +- tests/request/request.sh | 2 +- 18 files changed, 367 insertions(+), 273 deletions(-) diff --git a/qml/components/CatalogGrid.qml b/qml/components/CatalogGrid.qml index 3fe6464..2bb3603 100644 --- a/qml/components/CatalogGrid.qml +++ b/qml/components/CatalogGrid.qml @@ -141,9 +141,9 @@ GridView { anchors.rightMargin: 5//10 anchors.top: parent.top anchors.topMargin: 5//10 - property bool disabled: true + property bool disabled: !User.hasFavorited(modelData.key) icon.source: "qrc:/assets/images/heart.png" - icon.color: NeroshopComponents.Style.disabledColor//"#ffffff" + icon.color: heartIconButton.disabled ? "#808080" : "#e05d5d" icon.height: 24; icon.width: 24 background: Rectangle { color: "transparent" @@ -154,10 +154,12 @@ GridView { if(disabled) { disabled = false icon.color = "#e05d5d" + User.addToFavorites(modelData.key) } else { disabled = true - icon.color = NeroshopComponents.Style.disabledColor + icon.color = "#808080" + User.removeFromFavorites(modelData.key) } } MouseArea { diff --git a/qml/components/ProductDialog.qml b/qml/components/ProductDialog.qml index 5eb09e7..b6efb91 100644 --- a/qml/components/ProductDialog.qml +++ b/qml/components/ProductDialog.qml @@ -310,7 +310,7 @@ Popup { currentIndex = find("Miscellaneous") } function reset() { - let subcategories = Backend.getSubCategoryList(Backend.getCategoryIdByName(productCategoryBox.currentText)) + let subcategories = Backend.getSubCategoryList(Backend.getCategoryIdByName(productCategoryBox.currentText), true) addSubCategoryButton.visible = (subcategories.length > 0) subCategoryRepeater.model = 0 // reset } @@ -337,7 +337,7 @@ Popup { horizontalAlignment: Text.AlignHCenter } onClicked: { - let subcategories = Backend.getSubCategoryList(Backend.getCategoryIdByName(productCategoryBox.currentText)) + let subcategories = Backend.getSubCategoryList(Backend.getCategoryIdByName(productCategoryBox.currentText), true) if(subCategoryRepeater.count == 1) { console.log("Cannot add no more than 1 subcategories") return @@ -358,7 +358,7 @@ Popup { function getSubCategoryStringList() { let subCategoryStringList = [] - let subcategories = Backend.getSubCategoryList(Backend.getCategoryIdByName(productCategoryBox.currentText)) + let subcategories = Backend.getSubCategoryList(Backend.getCategoryIdByName(productCategoryBox.currentText), true) for(let i = 0; i < subcategories.length; i++) { subCategoryStringList[i] = subcategories[i].name//console.log(parent.parent.parent.categoryStringList[i])//console.log(categories[i].name) } @@ -785,6 +785,8 @@ Popup { productConditionBox.currentText, productLocationBox.currentText ) + // Save product thumbnail + Backend.saveProductThumbnail(productImages[0].source, listing_key) // Save product image(s) to datastore folder for (let i = 0; i < productImages.length; i++) { Backend.saveProductImage(productImages[i].source, listing_key) diff --git a/qml/components/TagField.qml b/qml/components/TagField.qml index aa51faa..f4d1da7 100644 --- a/qml/components/TagField.qml +++ b/qml/components/TagField.qml @@ -104,7 +104,7 @@ Item { Layout.preferredHeight: 50//height: 30 placeholderText: "Add tags (comma-separated)" - onAccepted: { + onEditingFinished: { if (tagInput.text.trim() !== "") { let tags = tagInput.text.split(",") tags = tags.map(function(tag) { return tag.trim() }) diff --git a/src/core/category.hpp b/src/core/category.hpp index b682957..61fd308 100644 --- a/src/core/category.hpp +++ b/src/core/category.hpp @@ -44,26 +44,40 @@ const std::vector predefined_categories = { { 21, "Real Estate, Property & Housing", "", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAC4ElEQVR4nO2ZPWgUURDHN1FEQQ0RIxiRoE0g2IiNgfRaGBRjSLAINn4UVkGwUJtUIY2VgYhgJ3jgV6EgEQIWNqIighFUEFQQsdDgF8b4k4ezOLfs3u3d7t7t5uYHw3HzZt6+98+8j9t4nmEYhmEYhgIosfwoeXHBBMAqgOWHLQHP9oB0NsF5YBToktiNwBjwpkLOe2CX2JGImN8qZrBKOe9TsWE2l9USeAasj8jpAl5H5E2ruJXAp5CYRRWzrYoAPVXGfyMrAQ6omL3ARfepfCMReXsC/V9OSwDgKHAsYE+yEqBb2lcD38X3DVgr/nUhOZ+BVYH+96cogFs6cUhFgC3SvgL4qPxXgRmx4ICuqH4H5HMN8LWIAhxSMTuB+zEePCLxG9zaVPnXiyjAS7frB2J3A7cj4n/6myZwEPjiNkH5PpaGACFjP5elAMhxNxiS4yb0i3LuqPYL4utXFbFYRAF8HgNDgbwpyjmu2l6I76zy3UthCdwFZpW9avRNcEblbVX+JWCzatsutkn5ThZpD5hV7e6s1ehJ+cvgQYznOMH+FEWAd0C7GuCC+D+oja1DxZ9W/Q2578r6VNvDogjgGFUx3e5m6N8NxHeY//Qq/1vKmVJtZ0IEaAc6A9YTIUBniN0kIwEWgtdalbNDqsHxXPl7Q/p5pNr7ggJE9N9Rw2+BUtab4BxwSu7+J4Brcub7PAUmxW6F5C/JieHH/BDfZAU7r/Knq8TOZy1AETEBPKuAmGBLgJbfA8alCrKy4L0A8WX5zHEvL5D0nC46mABYBWBLoMB7ANCmXnFVJGkFxHkGcMn/qZ6ryTsaJEBjRKDGyTdYgGxFoI7JN0GAbESgzsk3SYB0ReDf5N2/vOoios9+YDhg/SkKgIy5rWl/eZ9EA0gmQLJKIIXJ50CA+kQgpcnnRIDaRQAmUnpwXgRwTDTrhchwQksLeyfoNakC8oIJ4FkFxIRWXwKGYRiGYXitwF+FAy8M28uvbgAAAABJRU5ErkJggg=="}, { 22, "Luggage & Travel", "", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAC9klEQVR4nO2bPWjVUBiG38+K2C7iLzhZVyc7O/iDojhY3HSxautYFQQXF0HB2cEiKCLqIEoFCwoiaKU4V0REKFpxrFY61EFrfRyuQr3kJLnJPTkxNw90yTnN95435+R+J/ki1dTU1HQw5uOkwFFJ+5sOz0gaNjN8xCwVwAGiORFaWyEA3cB8hAFzwMbQ+goBGHXMgjuhtRUCcMRhAEDz/aF6AGuABYcBU0B3aI3eAZ7FzIKLofV5BzgVY8B3YEtojV4BNgG/YkyYALzkIqUBmIwxAGAotEavAOcTDJgFNoTW6Q1ga4IBALdD6/QK8CGFCXtCaFtWUJyxFH1GqGpuAOxMMQMALoTW6gWgC/icwoDCc4PIJQAMAveW/A3mCWJmi5Iep+i6QtJVQucGwLGmK7MAbMt5zoMplwF5Dc8NsDlC1CdgXY5z9gDfUhoQPjcAPkYIe0SO6Qk8bGEW3GrneLKIvekQdibHOY+3YADA7naOKYrlMW3jkgYijl8C5iV9zRBvZYv9R4BzGeL8kDRtZq+TOjqnM9AraTpD8DLxTtJJM3vq6hC7noFpSb3tVlUwi5IOm9n9qMakVHi8/XoKp0vSNRy/YEkGvGi/niCsknQoqqETZsBf+qIOFrUbLAORr+SSDNjhQUgoJqMOJhmw3YOQEMxJuhvV0AkzYFHSkJnNRjU6DfiTCP3vOcBbSXvNbNTVIS4Vdl39BUnDypYKr5d0pYX+U5KypsLvzexNhv9t4GkzNFi2zVCcWB/b4bEWBh9uO0wHPRBx3QSb1/9PNTYUX3LE2iepJ2Xfs2Y2kyNWalw3wWWSlu6enpjZy5yx+lP2m5B0I2esckGJH4sXArAr5dqv7IuRyykGX92yGUr8ctQ7QF+KwVf39Th1gQSvEgyobokMjSKpOKpdJAWcjhl8NX/zlwI8jzGg2oWSwFo6uVQWGIi5+h1RLP3AMfjql8vT6R9MAP2Oq1+6T2biHormYbX+fZ4gNT6auu4pXk1NTU1NFn4DHMdp490i7dkAAAAASUVORK5CYII="}, { 23, "Business, Industrial & Scientific", "", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAADDUlEQVR4nO2ZvWsUQRyG30lSaCJiVLSKYAoxooJIIIWiWImFYJcEYmnhPyD4B6iNpcFCUAjEkAQsRC20ERTxA4JFijSCImgR/IhJUHPJY3GJKN7uzsztZO5knubgbnbe9/fu7MzsnJRIJBKJRCLRwABbgBd4ENt73dRTvE0AbY5mdknqltQpaVbSlDFm3q80K71OSQ8lHQ6lYWOiFTgLvK4R8BJwBzgUQLcTeOV7521HQJGJrcAjC50KcKGk2ksr3iaAzEcA2CDpnqQ+C8+tkq4AFWPMVftS/9JrkXRK0vHVz56MppOSxn00XA1d8gj8J7DfQ6sLeG7R/xjgNG95QXXoL3gEAHDbUWsTMN0wxa+aGvIsPhTjBCq+JeP7eMvOv0xIGjTGVEJ0nhXA9hBiHjxVwOKl7AAWQgk60iepP6RAVgAzIUUdaJV0CxgIJWBqfQn0SJrO+r2AKUmXHdp3SLomqT2nzbKkIWOM0wpTF8B9zxn7tIfWGYqX3QowGKLWLFPdwFfH4icBn1EjoAe4CbwFlhslhKPAF8viPwB5w9hF9xgw7xh+Tcowsxu4C6wUaK0A+0qof023lBDK8iNgDzBcoHe9NEGVE0KZfgS0A7M5eovAtpI1jwBzoQLI2gfUxBizKOlGTpONks659Gmh+UTV1+NvZfb7u3/XC4AuSW+UfZbwXlK3MWapHmM1dA9I2ut6nTFmokwfa2bGCkZesJ1bQwD0FgTwMrbH4ADPCkKwOUprXoD+ggDWb98eA6ANeJcTwBLVCbOhcVoG/2T1kGI4p0mbpPO+/TcFVM/v83Zqn4CO2D7z8B4BkmSM+SxpJKdJp6ShejQaHqrvCFmvrwAzVP/0+H8BHhSsCCdje6wb4CAwCnwsKHa9mQceAwN4HsbYFD8I/Ihaph0jlP24Ub3zzVD8Ghdd6iscMsCopGZ6uZmTtNMY892msc1wOVGfn3Vns6Re28Y2Aezw9xINa882AYSZWcNiPRH+3xsUC1IAsQ3EJgUQ20BsUgCxDcQmBRDbQCKRSCQSiUQsfgGI7rZpsWTP5QAAAABJRU5ErkJggg=="}, - { 24, "Illegal", "Banned and/or prohibited items", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAFDUlEQVR4nO2bzW9WRRTGn2ljEaVFSghl40fStC5cYcNOSXVjQmo0fqAsWGI1oWyQmFQihkDUFQQ2xqVGoqa6smGPfwENkmoMpUHBapR+CG2I/bmYt0rrmfs5975NeJ/lvTPnOee5c+ecOzNXaqGFFlq4h+HqIgK2S3pCUr+kRyQ9JGlT4/aCpD8lXZX0g6QJ59xMXb5VAqANeAY4C3xPflwCzgCDQFuz48kMYCvwHjBdIOgQrjZsdjc7viCAzcBHwHzEwNdiHvgQ6Gp2vKsA7AOuVxj4WvwCvB7D91KTYONJfCLp1RzdFiRNSbohaV5Sm6QHJfVI6pV0fw5b5yS94Zybz9EnDoDHgR8zPK1FYBw4DOwkYULDT5z9wAFgrNE3DZNAX52xC9gF/Jbi2AzwPj79FeXZAozgJ8E0roGYMSY5tYvkie4WcATIM5TTODuAg8DNBN65ykXAD/ukJ3+BCocj0IN/nZJGQjX8QBfJ7/wyMFQJ+Wo/HDDa4LMwCXRWQfxFQvArWAT2RCe3/dkP3An48Xlssn0Zgm+WCKGRsDcWyWbCRU6IvE4RRgM+/EyMVwFf3lq4AAwRztW1iICvHUIT48myxrdip7xbNGZbYM86EKEHO0XOUeYDCjgWCOztNe3WgwgjAf6jRQ22YX/SzgAbjfbPAbcDTiwBz5eOMtnf+4Apg3uKIusJwLOBYI4l9GnqSAAOBbh3FzF21jB0m5TavpkiAN0B7tNFjFnLWOMZ+zZThG8Mzom8RrZj5/jDOWw0RQRg2OBbBrblMRJ6/3fmdKZ2EfAfbBYG8xh5yzAwT4HZtG4RgHbsbDRstQ8F9Khxbco5t5zXIefct5JekrRk3N4gaSymCM65vyX9ZNyyYgoKYK26Xi/hVK0iSLI2VTZbDUMCbDKu/VXYHf0rwguSFo3bGyR9TbxiyVoktWIKCmCh9Daac+68pBdli9Ah6atIIpC1YUiABeNalFWWhggvy34dOiR9GeF1sJ62FVNQgDnjWvY8moIa5oQdxrVZq2FIgCnjWm+RNBhCVSIA7QpksTxGQoVQf16HMnBFrROAgYCtXIVQqBQ+kDvCbHzRRMDvSaxFvlK4YeiSYWgsd3TZ+aKIAJw3+l8s4tCZgCNbchvLzllKBPzSmNX/VBFnBgOOjBSOMBtvYRGA44F+TxdxxAFXDGPTQEepKNO5cy+vAQ9gb9tNAcWKOPyxFAsHS0eZzp1rJADvBNoWWxRtGO3GLy2vxU2gp3SU6fyZRMCfKbBGzCxl5yzgg4AD49RweiuDCEPAd4H7J2I40IU/k2NhNEKMWXxIEiG0PXeNWLvEwGsJ5PujkKT7kCSChVdiO3AuQHRnHYrwaRXknfjDB6GRMErRdJPPjyHCwx7gMmAufsQg78NvjYUwToXZAT/bhyY8gF+B3qr4V5wYwE6NK7iJ36iMViwBG/F5PlQcgU95T8biTHNoIGUkgK8YD1Fiexpf2x8n/UjejdqCv8u5PsJzwt1YxG9XDeM3LdoTbLY3xD2C/6rLMuFdpsSwL3tUtlPSx5LynNtdkl+3Xzkqi/x64w5Jj0n639Z7Aj6T9KZzzlzvqw3AXvyZnLpwjdh5vizwafIkyRNkWcwCJ6jiHGAs4D+gjmKf1iiKK8C7VLgYEx349YTdwGlgguTiZS2WgYvAKeApKiyw6vxpapv++2nqYUndWv3T1B+SpiVNyv809XtdvrXQQgst3LP4B1dCXq0t0BR7AAAAAElFTkSuQmCC"}, + { 24, "Weapons & Firearms", "Firearms;Ammunition;Explosives", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB5klEQVR4nO2Yv0scQRhAJ5ggYto7q2gl1yVlzEWQqLUkhVYXbAxiZy/X2pgoiBBEQSvFQv+CNIFDDxFNQMEyAY0hRYJVxF8vjI64LntkcWacHZkHwy7D7rffW3Zmvh0hAoFAIBCwDNAEbKnWJHwEyAHbXCPPc3ecQx7YVM+Xx3zaG0vAD/ygUkuiAzjDI0QNkQqeIRIkXuAhIkFkgnsisoOHiJhEM35SvRKoA3qAVfziDPgANFyJrOEfv4Bi/JM6wD/GkwZ4P/7xvNYi+FrVMKdkn0/Ag0SRiFA98M7QQJyWbw54nPCcC4RNgIfAuabEG+AlsAi0uRTR4SPQDhxFxN5G4svpXnJuW+SJlgYUgI1Y31Ik/lPVt2dbZFBDQn6Sj4DjWH8pEn9G9c3ZFvmqIXIoZxSgDxgDpmTVEIndpWZG2Z7ZlHiFHt8SYkqxFmAE+KuuG7UmIQGWsc/kf9cBHVT1e2IhcTlu9oEVoFMryTQAZQNJTwvXcHPL57aUXUu0YIZ+1yIDhkS6XIvMGhIpuBb5bEik0bXIngGJ304lJOofWJcvwjXAdwMi81kQWTcgMpwFkfcGRIpZEOnWlNi1WgimRZXaVQ2RXpEVgFbgp5HNMtdwWcovAH9SCMjSfMh1zoFAQKTiH6A/KlfoMzZ2AAAAAElFTkSuQmCC"}, + { 25, "Illegal", "Banned and/or prohibited items", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAFDUlEQVR4nO2bzW9WRRTGn2ljEaVFSghl40fStC5cYcNOSXVjQmo0fqAsWGI1oWyQmFQihkDUFQQ2xqVGoqa6smGPfwENkmoMpUHBapR+CG2I/bmYt0rrmfs5975NeJ/lvTPnOee5c+ecOzNXaqGFFlq4h+HqIgK2S3pCUr+kRyQ9JGlT4/aCpD8lXZX0g6QJ59xMXb5VAqANeAY4C3xPflwCzgCDQFuz48kMYCvwHjBdIOgQrjZsdjc7viCAzcBHwHzEwNdiHvgQ6Gp2vKsA7AOuVxj4WvwCvB7D91KTYONJfCLp1RzdFiRNSbohaV5Sm6QHJfVI6pV0fw5b5yS94Zybz9EnDoDHgR8zPK1FYBw4DOwkYULDT5z9wAFgrNE3DZNAX52xC9gF/Jbi2AzwPj79FeXZAozgJ8E0roGYMSY5tYvkie4WcATIM5TTODuAg8DNBN65ykXAD/ukJ3+BCocj0IN/nZJGQjX8QBfJ7/wyMFQJ+Wo/HDDa4LMwCXRWQfxFQvArWAT2RCe3/dkP3An48Xlssn0Zgm+WCKGRsDcWyWbCRU6IvE4RRgM+/EyMVwFf3lq4AAwRztW1iICvHUIT48myxrdip7xbNGZbYM86EKEHO0XOUeYDCjgWCOztNe3WgwgjAf6jRQ22YX/SzgAbjfbPAbcDTiwBz5eOMtnf+4Apg3uKIusJwLOBYI4l9GnqSAAOBbh3FzF21jB0m5TavpkiAN0B7tNFjFnLWOMZ+zZThG8Mzom8RrZj5/jDOWw0RQRg2OBbBrblMRJ6/3fmdKZ2EfAfbBYG8xh5yzAwT4HZtG4RgHbsbDRstQ8F9Khxbco5t5zXIefct5JekrRk3N4gaSymCM65vyX9ZNyyYgoKYK26Xi/hVK0iSLI2VTZbDUMCbDKu/VXYHf0rwguSFo3bGyR9TbxiyVoktWIKCmCh9Daac+68pBdli9Ah6atIIpC1YUiABeNalFWWhggvy34dOiR9GeF1sJ62FVNQgDnjWvY8moIa5oQdxrVZq2FIgCnjWm+RNBhCVSIA7QpksTxGQoVQf16HMnBFrROAgYCtXIVQqBQ+kDvCbHzRRMDvSaxFvlK4YeiSYWgsd3TZ+aKIAJw3+l8s4tCZgCNbchvLzllKBPzSmNX/VBFnBgOOjBSOMBtvYRGA44F+TxdxxAFXDGPTQEepKNO5cy+vAQ9gb9tNAcWKOPyxFAsHS0eZzp1rJADvBNoWWxRtGO3GLy2vxU2gp3SU6fyZRMCfKbBGzCxl5yzgg4AD49RweiuDCEPAd4H7J2I40IU/k2NhNEKMWXxIEiG0PXeNWLvEwGsJ5PujkKT7kCSChVdiO3AuQHRnHYrwaRXknfjDB6GRMErRdJPPjyHCwx7gMmAufsQg78NvjYUwToXZAT/bhyY8gF+B3qr4V5wYwE6NK7iJ36iMViwBG/F5PlQcgU95T8biTHNoIGUkgK8YD1Fiexpf2x8n/UjejdqCv8u5PsJzwt1YxG9XDeM3LdoTbLY3xD2C/6rLMuFdpsSwL3tUtlPSx5LynNtdkl+3Xzkqi/x64w5Jj0n639Z7Aj6T9KZzzlzvqw3AXvyZnLpwjdh5vizwafIkyRNkWcwCJ6jiHGAs4D+gjmKf1iiKK8C7VLgYEx349YTdwGlgguTiZS2WgYvAKeApKiyw6vxpapv++2nqYUndWv3T1B+SpiVNyv809XtdvrXQQgst3LP4B1dCXq0t0BR7AAAAAElFTkSuQmCC"}, }; const std::vector predefined_subcategories = { // For each category is a subcategory (for example, the books, movies, and music categories can have the digital goods subcategory if they are digital rather than physical) // Digital Goods - { static_cast(predefined_categories.size() + 1), predefined_categories[5].name, predefined_categories[5].description, predefined_categories[5].thumbnail, 7 }, - { 26, predefined_categories[5].name, predefined_categories[5].description, predefined_categories[5].thumbnail, 8 }, - { 27, predefined_categories[5].name, predefined_categories[5].description, predefined_categories[5].thumbnail, 9 }, + { static_cast(predefined_categories.size() + 0), predefined_categories[5].name, predefined_categories[5].description, predefined_categories[5].thumbnail, 7 }, + { static_cast(predefined_categories.size() + 1), predefined_categories[5].name, predefined_categories[5].description, predefined_categories[5].thumbnail, 8 }, + { static_cast(predefined_categories.size() + 2), predefined_categories[5].name, predefined_categories[5].description, predefined_categories[5].thumbnail, 9 }, // Illegal - { 28, predefined_categories[24].name, predefined_categories[24].description, predefined_categories[24].thumbnail, 0 }, - { 29, predefined_categories[24].name, predefined_categories[24].description, predefined_categories[24].thumbnail, 5 }, - { 30, predefined_categories[24].name, predefined_categories[24].description, predefined_categories[24].thumbnail, 6 }, - { 31, predefined_categories[24].name, predefined_categories[24].description, predefined_categories[24].thumbnail, 7 }, - { 32, predefined_categories[24].name, predefined_categories[24].description, predefined_categories[24].thumbnail, 8 }, - { 33, predefined_categories[24].name, predefined_categories[24].description, predefined_categories[24].thumbnail, 23 }, - { 34, predefined_categories[24].name, predefined_categories[24].description, predefined_categories[24].thumbnail, 19 }, + { static_cast(predefined_categories.size() + 3), predefined_categories[25].name, predefined_categories[25].description, predefined_categories[25].thumbnail, 0 }, + { static_cast(predefined_categories.size() + 4), predefined_categories[25].name, predefined_categories[25].description, predefined_categories[25].thumbnail, 5 }, + { static_cast(predefined_categories.size() + 5), predefined_categories[25].name, predefined_categories[25].description, predefined_categories[25].thumbnail, 6 }, + { static_cast(predefined_categories.size() + 6), predefined_categories[25].name, predefined_categories[25].description, predefined_categories[25].thumbnail, 7 }, + { static_cast(predefined_categories.size() + 7), predefined_categories[25].name, predefined_categories[25].description, predefined_categories[25].thumbnail, 8 }, + { static_cast(predefined_categories.size() + 8), predefined_categories[25].name, predefined_categories[25].description, predefined_categories[25].thumbnail, 19 }, + { static_cast(predefined_categories.size() + 9), predefined_categories[25].name, predefined_categories[25].description, predefined_categories[25].thumbnail, 23 }, + { static_cast(predefined_categories.size() + 10), predefined_categories[25].name, predefined_categories[25].description, predefined_categories[25].thumbnail, 24 }, - //{ 0, , }, + // All categories + { static_cast(predefined_categories.size() + 11), predefined_categories[0].name, predefined_categories[0].description, predefined_categories[0].thumbnail, 25 }, + { static_cast(predefined_categories.size() + 12), predefined_categories[5].name, predefined_categories[5].description, predefined_categories[5].thumbnail, 25 }, + { static_cast(predefined_categories.size() + 13), predefined_categories[6].name, predefined_categories[6].description, predefined_categories[6].thumbnail, 25 }, + { static_cast(predefined_categories.size() + 14), predefined_categories[7].name, predefined_categories[7].description, predefined_categories[7].thumbnail, 25 }, + { static_cast(predefined_categories.size() + 15), predefined_categories[8].name, predefined_categories[8].description, predefined_categories[8].thumbnail, 25 }, + { static_cast(predefined_categories.size() + 16), predefined_categories[19].name, predefined_categories[19].description, predefined_categories[19].thumbnail, 25 }, + { static_cast(predefined_categories.size() + 17), predefined_categories[23].name, predefined_categories[23].description, predefined_categories[23].thumbnail, 25 }, + { static_cast(predefined_categories.size() + 18), predefined_categories[24].name, predefined_categories[24].description, predefined_categories[24].thumbnail, 25 }, + + { static_cast(predefined_categories.size() + 19), predefined_categories[7].name, predefined_categories[7].description, predefined_categories[7].thumbnail, 5 }, + { static_cast(predefined_categories.size() + 20), predefined_categories[8].name, predefined_categories[8].description, predefined_categories[8].thumbnail, 5 }, + { static_cast(predefined_categories.size() + 21), predefined_categories[9].name, predefined_categories[9].description, predefined_categories[9].thumbnail, 5 }, }; //----------------------------------------------------------------------------- diff --git a/src/core/image.hpp b/src/core/image.hpp index bb7058b..ee16203 100644 --- a/src/core/image.hpp +++ b/src/core/image.hpp @@ -8,7 +8,8 @@ namespace neroshop { struct Image { std::string name; // base name + ext size_t size; // bytes - unsigned int id = 0; // The specific order in which images are displayed//bool thumbnail; + unsigned int id = 0; // The specific order in which images are displayed + std::string source; // never stored in DHT }; } diff --git a/src/core/protocol/p2p/serializer.cpp b/src/core/protocol/p2p/serializer.cpp index bc16142..a158eaf 100644 --- a/src/core/protocol/p2p/serializer.cpp +++ b/src/core/protocol/p2p/serializer.cpp @@ -137,7 +137,7 @@ std::pair*/> neroshop::Serializer image_obj["size"] = image.size; image_obj["id"] = image.id; bool is_thumbnail = ((images.size() == 1) || (image.id == 0)); - if(is_thumbnail) { // TODO: store only thumbnail images in DHT + if(is_thumbnail) { std::cout << image.name << " \033[1;35mwill be used as thumbnail\033[0m\n"; } diff --git a/src/core/seller.cpp b/src/core/seller.cpp index ecbdd0a..fb22367 100644 --- a/src/core/seller.cpp +++ b/src/core/seller.cpp @@ -668,10 +668,10 @@ neroshop::User * neroshop::Seller::on_login(const neroshop::Wallet& wallet) { // dynamic_cast(user)->set_account_type(UserAccountType::Seller); //------------------------------- /*// load orders - dynamic_cast(user)->load_orders(); + dynamic_cast(user)->load_orders();*/ // load wishlists dynamic_cast(user)->load_favorites(); - // load customer_orders + /*// load customer_orders static_cast(user)->load_customer_orders();*/ // Load cart (into memory) user->get_cart()->load(user->get_id()); diff --git a/src/core/tools/base64.cpp b/src/core/tools/base64.cpp index c629cf7..9bf2e9b 100644 --- a/src/core/tools/base64.cpp +++ b/src/core/tools/base64.cpp @@ -3,6 +3,7 @@ #include #include #include +#include std::string neroshop::base64_encode(const std::string& input) { // Create a BIO object for Base64 encoding @@ -55,6 +56,77 @@ std::string neroshop::base64_decode(const std::string& encoded) { return decoded_data; } +//---------------------------------------------------------------------------- + +std::string neroshop::base64_image_encode(const std::string& image_path) { + // Open the image file + std::ifstream image_file(image_path, std::ios::binary); + if (!image_file.is_open()) { + // Error handling for failed file opening + return ""; + } + + // Get the size of the file + image_file.seekg(0, std::ios::end); + size_t file_size = image_file.tellg(); + image_file.seekg(0, std::ios::beg); + + // Read the image data into a buffer + std::vector buffer(file_size); + image_file.read(buffer.data(), file_size); + + // Create a BIO object for Base64 encoding + BIO* b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + + // Create a BIO object for memory buffering + BIO* mem = BIO_new(BIO_s_mem()); + BIO_push(b64, mem); + + // Write input data to the BIO for encoding + BIO_write(b64, buffer.data(), static_cast(buffer.size())); + BIO_flush(b64); + + // Read the encoded data from the BIO + BUF_MEM* mem_buf; + BIO_get_mem_ptr(b64, &mem_buf); + + // Copy the encoded data to a string + std::string encoded_data(mem_buf->data, mem_buf->length); + + // Cleanup + BIO_free_all(b64); + + return encoded_data; +} + +std::vector neroshop::base64_image_decode(const std::string& encoded) { + // Create a BIO object for Base64 decoding + BIO* b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + + // Create a BIO object for memory buffering + BIO* mem = BIO_new_mem_buf(encoded.c_str(), static_cast(encoded.length())); + BIO_push(b64, mem); + + // Determine the size of the decoded data + size_t max_decoded_length = (encoded.length() * 3) / 4; + std::vector decoded_data(max_decoded_length); + + // Decode the data + int decoded_length = BIO_read(b64, decoded_data.data(), static_cast(decoded_data.size())); + + // Resize the vector to the actual decoded length + decoded_data.resize(decoded_length); + + // Cleanup + BIO_free_all(b64); + + return decoded_data; +} + +//---------------------------------------------------------------------------- + /*int main() { std::string input = "Hello, World!"; diff --git a/src/core/tools/base64.hpp b/src/core/tools/base64.hpp index be325d7..d7f2476 100644 --- a/src/core/tools/base64.hpp +++ b/src/core/tools/base64.hpp @@ -2,10 +2,14 @@ #include #include +#include namespace neroshop { extern std::string base64_encode(const std::string& input); extern std::string base64_decode(const std::string& encoded); +// untested +extern std::string base64_image_encode(const std::string& image_path); +extern std::vector base64_image_decode(const std::string& encoded); } diff --git a/src/core/user.cpp b/src/core/user.cpp index 77f5b6e..5a27ea3 100644 --- a/src/core/user.cpp +++ b/src/core/user.cpp @@ -11,7 +11,7 @@ #include //////////////////// -neroshop::User::User() : id(""), logged(false), account_type(UserAccountType::Guest), cart(nullptr), order_list({}), favorites_list({}) { +neroshop::User::User() : id(""), logged(false), account_type(UserAccountType::Guest), cart(nullptr), order_list({}), favorites({}) { cart = std::unique_ptr(new Cart()); } //////////////////// @@ -24,7 +24,7 @@ neroshop::User::~User() // clear orders order_list.clear(); // this should reset (delete) all orders // clear favorites - favorites_list.clear(); // this should reset (delete) all favorites + favorites.clear(); // this should reset (delete) all favorites #ifdef NEROSHOP_DEBUG std::cout << "user deleted\n"; #endif @@ -239,18 +239,10 @@ void neroshop::User::add_to_cart(const std::string& product_id, int quantity) { cart->add(this->id, product_id, quantity); } //////////////////// -void neroshop::User::add_to_cart(const neroshop::Product& item, int quantity) { - add_to_cart(item.get_id(), quantity); -} -//////////////////// void neroshop::User::remove_from_cart(const std::string& product_id, int quantity) { cart->remove(this->id, product_id, quantity); } //////////////////// -void neroshop::User::remove_from_cart(const neroshop::Product& item, int quantity) { - remove_from_cart(item.get_id(), quantity); -} -//////////////////// void neroshop::User::clear_cart() { cart->empty(); } @@ -331,78 +323,92 @@ void neroshop::User::load_orders() { //////////////////// // favorite-or-wishlist-related stuff //////////////////// -void neroshop::User::add_to_favorites(const std::string& product_id) { -#if defined(NEROSHOP_USE_POSTGRESQL) +void neroshop::User::add_to_favorites(const std::string& listing_key) { + db::Sqlite3 * database = neroshop::get_database(); + // check if item is already in favorites so that we do not add the same item more than once - std::string item_name = database->get_text_params("SELECT name FROM item WHERE id = $1", { product_id }); - bool favorited = (database->get_text_params("SELECT EXISTS(SELECT product_ids FROM favorites WHERE $1 = ANY(product_ids) AND user_id = $2)", { product_id, std::to_string(this->id) }) == "t") ? true : false; - if(favorited) { neroshop::print("\"" + item_name + "\" is already in your favorites", 2); return; /* exit function */} + bool favorited = database->get_integer_params("SELECT EXISTS(SELECT listing_key FROM favorites WHERE listing_key = ?1 AND user_id = ?2)", { listing_key, this->id }); + if(favorited) { neroshop::print("\"" + listing_key + "\" is already in your favorites", 2); return; } // add item to favorites - database->execute_params("UPDATE favorites SET product_ids = array_append(product_ids, $1::integer) WHERE user_id = $2", { product_id, std::to_string(this->id) }); - // store in vector as well - favorites_list.push_back(std::make_shared(product_id));//(std::unique_ptr(new neroshop::Product(product_id))); - neroshop::print("\"" + item_name + "\" has been added to your favorites", 3);//if(std::find(favorites_list.begin(), favorites_list.end(), product_id) == favorites_list.end()) { favorites_list.push_back(product_id); neroshop::print("\"" + item_name + "\" has been added to your favorites", 3); }// this works for a favorite_list that stores integers (product_ids) rather than the item object itself -#endif -} -//////////////////// -void neroshop::User::add_to_favorites(const neroshop::Product& item) { - add_to_favorites(item.get_id()); + int rescode = database->execute_params("INSERT INTO favorites (user_id, listing_key) VALUES (?1, ?2);", { this->id, listing_key }); + if(rescode != SQLITE_OK) { + neroshop::print("failed to add item to favorites", 1); + return; + } + // store in memory as well + favorites.push_back(listing_key); + if(std::find(favorites.begin(), favorites.end(), listing_key) != favorites.end()) { + neroshop::print("\"" + listing_key + "\" has been added to your favorites", 3); + } } //////////////////// -void neroshop::User::remove_from_favorites(const std::string& product_id) { -#if defined(NEROSHOP_USE_POSTGRESQL) +void neroshop::User::remove_from_favorites(const std::string& listing_key) { + db::Sqlite3 * database = neroshop::get_database(); + // check if item has already been removed from favorites so that we don't have to remove it more than once - std::string item_name = database->get_text_params("SELECT name FROM item WHERE id = $1", { product_id }); - bool favorited = (database->get_text_params("SELECT EXISTS(SELECT product_ids FROM favorites WHERE $1 = ANY(product_ids) AND user_id = $2)", { product_id, std::to_string(this->id) }) == "t") ? true : false; - if(!favorited) return; // exit function ////{ neroshop::print("\"" + item_name + "\" was not found in your favorites list", 2); return; } - // remove item from favorites - database->execute_params("UPDATE favorites SET product_ids = array_remove(product_ids, $1::integer) WHERE user_id = $2", { product_id, std::to_string(this->id) }); + bool favorited = database->get_integer_params("SELECT EXISTS(SELECT listing_key FROM favorites WHERE listing_key = ?1 AND user_id = ?2)", { listing_key, this->id }); + if(!favorited) { + auto it = std::find(favorites.begin(), favorites.end(), listing_key); + if (it != favorites.end()) { favorites.erase(it); } // remove from vector if found in-memory, but not found in database + neroshop::print("\"" + listing_key + "\" is not in your favorites", 2); + return; + } + // remove item from favorites (database) + int rescode = database->execute_params("DELETE FROM favorites WHERE listing_key = ?1 AND user_id = ?2;", { listing_key, this->id }); + if (rescode != SQLITE_OK) { + neroshop::print("failed to remove item from favorites", 1); + return; + } // remove from vector as well - for(const auto & favorites : favorites_list) { - if(favorites->get_id() != product_id) continue; // skip items whose ids do the match the product_id to be deleted - auto it = std::find(favorites_list.begin(), favorites_list.end(), favorites); - int item_index = it - favorites_list.begin();//std::cout << "favorites_list item index: " << item_index << std::endl; - favorites_list.erase(favorites_list.begin() + item_index); - if(std::find(favorites_list.begin(), favorites_list.end(), favorites) == favorites_list.end()) neroshop::print("\"" + item_name + "\" has been removed from your favorites", 1); // confirm that item has been removed from favorites_list - } -#endif -} -//////////////////// -void neroshop::User::remove_from_favorites(const neroshop::Product& item) { - remove_from_favorites(item.get_id()); + auto it = std::find(favorites.begin(), favorites.end(), listing_key); + if (it != favorites.end()) { + favorites.erase(it); + if(std::find(favorites.begin(), favorites.end(), listing_key) == favorites.end()) neroshop::print("\"" + listing_key + "\" has been removed from your favorites", 1); // confirm that item has been removed from favorites + } } //////////////////// void neroshop::User::clear_favorites() { -#if defined(NEROSHOP_USE_POSTGRESQL) - // first check if array is empty - int is_empty = database->get_integer_params("SELECT COUNT(*) FROM favorites WHERE product_ids = '{}' AND user_id = $1", { std::to_string(this->id) }); - if(is_empty) return; // array is empty so that means there is nothing to delete, exit function + db::Sqlite3 * database = neroshop::get_database(); + + // first check if favorites (database table) is empty + int favorites_count = database->get_integer_params("SELECT COUNT(*) FROM favorites WHERE user_id = ?1", { this->id }); + if(favorites_count <= 0) return; // table is empty so that means there is nothing to delete, exit function // clear all items from favorites - database->execute_params("UPDATE favorites SET product_ids = '{}' WHERE user_id = $1", { std::to_string(this->id) }); + database->execute_params("DELETE FROM favorites WHERE user_id = ?1", { this->id }); // clear favorites from vector as well - favorites_list.clear(); - if(favorites_list.empty()) neroshop::print("your favorites have been cleared");// confirm that favorites_list has been cleared -#endif + favorites.clear(); + if(favorites.empty()) neroshop::print("your favorites have been cleared"); // confirm that favorites has been cleared } //////////////////// void neroshop::User::load_favorites() { -#if defined(NEROSHOP_USE_POSTGRESQL) - std::string command = "SELECT unnest(product_ids) FROM favorites WHERE user_id = $1"; - std::vector param_values = { std::to_string(this->id).c_str() }; - PGresult * result = PQexecParams(database->get_handle(), command.c_str(), 1, nullptr, param_values.data(), nullptr, nullptr, 0); - int rows = PQntuples(result);//if(rows < 1) { PQclear(result); return; } - if (PQresultStatus(result) != PGRES_TUPLES_OK) { - neroshop::print("User::load_favorites(): Your favorites list is empty", 2); - PQclear(result);//exit(1); - return; // exit so that we don't double free "result" + favorites.clear(); + db::Sqlite3 * database = neroshop::get_database(); + std::string command = "SELECT DISTINCT listing_key FROM favorites WHERE user_id = ?1;"; + sqlite3_stmt * stmt = nullptr; + // Prepare (compile) statement + if(sqlite3_prepare_v2(database->get_handle(), command.c_str(), -1, &stmt, nullptr) != SQLITE_OK) { + neroshop::print("sqlite3_prepare_v2: " + std::string(sqlite3_errmsg(database->get_handle())), 1); + return; } - for(int i = 0; i < rows; i++) { - int product_id = std::stoi(PQgetvalue(result, i, 0)); - favorites_list.push_back(std::make_shared(product_id));//(std::unique_ptr(new neroshop::Product(product_id))); // store favorited_items for later use - neroshop::print("Favorited item (id: " + product_id + ") has been loaded"); + // Bind this->id to first argument + if(sqlite3_bind_text(stmt, 1, this->id.c_str(), this->id.length(), SQLITE_STATIC) != SQLITE_OK) { + neroshop::print("sqlite3_bind_text (arg: 1): " + std::string(sqlite3_errmsg(database->get_handle())), 1); + sqlite3_finalize(stmt); + return; + } + + while(sqlite3_step(stmt) == SQLITE_ROW) { + for(int i = 0; i < sqlite3_column_count(stmt); i++) { + std::string listing_key = (sqlite3_column_text(stmt, i) == nullptr) ? "NULL" : reinterpret_cast(sqlite3_column_text(stmt, i)); + if(listing_key == "NULL") continue; // Skip invalid columns + favorites.push_back(listing_key); // store favorited listings for later use + if(std::find(favorites.begin(), favorites.end(), listing_key) != favorites.end()) { + neroshop::print("Favorited item (" + listing_key + ") has been loaded"); + } + } } - PQclear(result); -#endif + + sqlite3_finalize(stmt); } //////////////////// //////////////////// @@ -690,20 +696,16 @@ std::vector neroshop::User::get_order_list() const { } //////////////////// //////////////////// -neroshop::Product * neroshop::User::get_favorite(unsigned int index) const { - if(index > (favorites_list.size() - 1)) throw std::out_of_range("neroshop::User::get_favorites(): attempt to access invalid index"); - return favorites_list[index].get(); +std::string neroshop::User::get_favorite(unsigned int index) const { + if(index > (favorites.size() - 1)) throw std::out_of_range("neroshop::User::get_favorites(): attempt to access invalid index"); + return favorites[index]; } //////////////////// unsigned int neroshop::User::get_favorites_count() const { - return favorites_list.size(); + return favorites.size(); } //////////////////// -std::vector neroshop::User::get_favorites_list() const { - std::vector favorites = {}; - for(const auto & item : favorites_list) {//for(int f = 0; f < favorites_list.size(); f++) { - favorites.push_back(item.get());//(favorites_list[f].get()); - } +std::vector neroshop::User::get_favorites() const { return favorites; } //////////////////// @@ -906,21 +908,13 @@ bool neroshop::User::has_purchased(const std::string& product_id) { // for regis return false; } //////////////////// -bool neroshop::User::has_purchased(const neroshop::Product& item) { - return has_purchased(item.get_id()); -} -//////////////////// -bool neroshop::User::has_favorited(const std::string& product_id) { +bool neroshop::User::has_favorited(const std::string& listing_key_or_id) { // since we loaded the favorites into memory when the app launched, we should be able to access the pre-loaded favorites and any newly added favorites in the current session without performing any database queries/operations - for(const auto & favorites : favorites_list) { - // if any favorites_list items' ids matches "product_id" then return true - if(favorites->get_id() == product_id) return true; + for(const auto & favorite : favorites) { + // if any favorites items' ids matches "product_id" then return true + if(favorite == listing_key_or_id) return true; } - return false;////return (std::find(favorites_list.begin(), favorites_list.end(), product_id) != favorites_list.end()); // this is good for when storing favorites as integers (product_ids) -} -//////////////////// -bool neroshop::User::has_favorited(const neroshop::Product& item) { - return has_favorited(item.get_id()); + return false;////return (std::find(favorites.begin(), favorites.end(), product_id) != favorites.end()); // this is good for when storing favorites as integers (product_ids) } //////////////////// //////////////////// diff --git a/src/core/user.hpp b/src/core/user.hpp index 37f9a09..3e29637 100644 --- a/src/core/user.hpp +++ b/src/core/user.hpp @@ -27,17 +27,13 @@ public: void logout(); // cart-related stuff (50% complete - cart class still needs some more work) void add_to_cart(const std::string& product_id, int quantity = 1); - void add_to_cart(const neroshop::Product& item, int quantity = 1); // use int and NOT unsigned int 'cause unsigned int assumes the arg will never be negative number, but when arg is negative, it converts it to some random positive number void remove_from_cart(const std::string& product_id, int quantity = 1); - void remove_from_cart(const neroshop::Product& item, int quantity = 1); void clear_cart(); // order-related stuff (50% complete - order class still needs some more work) void create_order(const std::string& shipping_address);// const;//void create_order(); // favorite-or-wishlist-related stuff (100% complete) void add_to_favorites(const std::string& product_id); - void add_to_favorites(const neroshop::Product& item); void remove_from_favorites(const std::string& product_id); - void remove_from_favorites(const neroshop::Product& item); void clear_favorites(); // avatar-related stuff (10% complete) void upload_avatar(const std::string& filename); @@ -58,9 +54,9 @@ public: neroshop::Order * get_order(unsigned int index) const; unsigned int get_order_count() const; std::vector get_order_list() const; - neroshop::Product * get_favorite(unsigned int index) const; + std::string get_favorite(unsigned int index) const; unsigned int get_favorites_count() const; - std::vector get_favorites_list() const; + std::vector get_favorites() const; // boolean bool is_guest() const; bool is_buyer() const; @@ -73,9 +69,7 @@ public: bool has_avatar() const; // item-related stuff - boolean bool has_purchased(const std::string& product_id); // checks if an item was previously purchased or not - bool has_purchased(const neroshop::Product& item); // checks if an item was previously purchased or not bool has_favorited(const std::string& product_id); // checks if an item is in a user's favorites or wishlist - bool has_favorited(const neroshop::Product& item); // checks if an item is in a user's favorites or wishlist // callbacks void on_registration(const std::string& name); // on registering an account //virtual User * on_login(const std::string& username);// = 0; // load all data: orders, reputation/ratings, settings // for all users @@ -105,7 +99,7 @@ private: std::string private_key; std::unique_ptr cart; std::vector> order_list; - std::vector> favorites_list; // I get the error "/usr/include/c++/9/bits/stl_uninitialized.h:127:72: error: static assertion failed: result type must be constructible from value type of input range" while trying to use unique_ptr so I'm stuck with a shared_ptr container for now + std::vector favorites; std::string get_private_key() const; }; } diff --git a/src/gui/backend.cpp b/src/gui/backend.cpp index 6b4eda4..9008bc7 100644 --- a/src/gui/backend.cpp +++ b/src/gui/backend.cpp @@ -14,6 +14,13 @@ #include // Note: QProcess is not supported on VxWorks, iOS, tvOS, or watchOS. #include #include +#include +#include +#include +#include +#include +#include +#include #include "../neroshop_config.hpp" #include "../core/version.hpp" @@ -34,7 +41,6 @@ #include "../core/category.hpp" #include "../core/tools/regex.hpp" #include "../core/crypto/rsa.hpp" -#include "../core/protocol/p2p/mapper.hpp" #include #include @@ -62,6 +68,23 @@ void neroshop::Backend::copyTextToClipboard(const QString& text) { } //---------------------------------------------------------------- //---------------------------------------------------------------- +QString neroshop::Backend::imageToBase64(const QImage& image) { + QByteArray byteArray; + QBuffer buffer(&byteArray); + buffer.open(QIODevice::WriteOnly); + image.save(&buffer, "PNG"); // You can choose a different format if needed + return QString::fromLatin1(byteArray.toBase64().data()); +} +//---------------------------------------------------------------- +QImage neroshop::Backend::base64ToImage(const QString& base64Data) { + QByteArray byteArray = QByteArray::fromBase64(base64Data.toLatin1()); + QImageReader reader(byteArray); + reader.setAutoTransform(true); + const QImage image = reader.read(); + return image; +} +//---------------------------------------------------------------- +//---------------------------------------------------------------- QStringList neroshop::Backend::getCurrencyList() const { QStringList currency_list; @@ -95,8 +118,7 @@ bool neroshop::Backend::isSupportedCurrency(const QString& currency) const { void neroshop::Backend::initializeDatabase() { db::Sqlite3 * database = neroshop::get_database(); database->execute("BEGIN;"); - //------------------------- - // Todo: Make monero_address the primary key and remove id. Also, replace all foreign key references from id to monero_address + // table users if(!database->table_exists("users")) { database->execute("CREATE TABLE users(name TEXT, monero_address TEXT NOT NULL PRIMARY KEY"//, UNIQUE" @@ -107,61 +129,37 @@ void neroshop::Backend::initializeDatabase() { // Notes: Display names are optional which means they can be an empty string but making the "name" column UNIQUE will not allow empty strings on multiple names ////database->execute("CREATE UNIQUE INDEX index_public_keys ON users (public_key);"); // This is commented out to allow multiple users to use the same public key, in the case of a user having two neroshop accounts? } - // products (represents both items and services) - if(!database->table_exists("products")) { - database->execute("CREATE TABLE products(uuid TEXT NOT NULL PRIMARY KEY);"); - database->execute("ALTER TABLE products ADD COLUMN name TEXT;"); - database->execute("ALTER TABLE products ADD COLUMN description TEXT;"); - //database->execute("ALTER TABLE products ADD COLUMN price REAL");// This should be the manufacturer's original price (won't be used though) // unit_price or price_per_unit - database->execute("ALTER TABLE products ADD COLUMN weight REAL;"); // kg // TODO: add weight to attributes - database->execute("ALTER TABLE products ADD COLUMN attributes TEXT;"); // attribute options format: "Color:Red,Green,Blue;Size:XS,S,M,L,XL"// Can be a number(e.g 16) or a text(l x w x h) - database->execute("ALTER TABLE products ADD COLUMN code TEXT;"); // product_code can be either upc (universal product code) or a custom sku - database->execute("ALTER TABLE products ADD COLUMN category_id INTEGER REFERENCES categories(id);"); - //database->execute("ALTER TABLE products ADD COLUMN subcategory_id INTEGER REFERENCES categories(id);"); - //database->execute("ALTER TABLE products ADD COLUMN ?col ?datatype;"); - //database->execute("CREATE UNIQUE INDEX ?index ON products (?col);"); - // the seller determines the final product price, the product condition and whether the product will have a discount or not - // Note: UPC codes can be totally different for the different variations(color, etc.) of the same product + + // mappings + if(!database->table_exists("mappings")) { + database->execute("CREATE VIRTUAL TABLE mappings USING fts5(search_term, key, content, tokenize='porter unicode61');"); } - // listings - if(!database->table_exists("listings")) { - database->execute("CREATE TABLE listings(uuid TEXT NOT NULL PRIMARY KEY, " - "product_id TEXT REFERENCES products(uuid) ON DELETE CASCADE, " // ON DELETE CASCADE keeps the parent table from being deleted until all child rows that references the parent are deleted first - "seller_id TEXT REFERENCES users(monero_address)" // alternative names: "store_id" + + // favorites (wishlists) + if(!database->table_exists("favorites")) { + database->execute("CREATE TABLE favorites(" + "user_id TEXT REFERENCES users(monero_address), " + "listing_key TEXT, " + "UNIQUE(user_id, listing_key)" ");"); - database->execute("ALTER TABLE listings ADD COLUMN quantity INTEGER;"); // stock available - database->execute("ALTER TABLE listings ADD COLUMN price REAL;"); // this is the final price of a product or list/sales price decided by the seller - database->execute("ALTER TABLE listings ADD COLUMN currency TEXT;"); // the fiat currency the seller is selling the item in - //database->execute("ALTER TABLE listings ADD COLUMN discount numeric(20,12);"); // alternative names: "seller_discount", or "discount_price" - //database->execute("ALTER TABLE listings ADD COLUMN ?col ?datatype;"); // discount_times_can_use - number of times the discount can be used - //database->execute("ALTER TABLE listings ADD COLUMN ?col ?datatype;"); // discounted_items_qty - number of items that the discount will apply to - //database->execute("ALTER TABLE listings ADD COLUMN ?col ?datatype;"); // discount_expiry - date and time that the discount expires (will be in UTC format) - //database->execute("ALTER TABLE listings ADD COLUMN ?col ?datatype;"); - database->execute("ALTER TABLE listings ADD COLUMN condition TEXT;"); // item condition - database->execute("ALTER TABLE listings ADD COLUMN location TEXT;"); - //database->execute("ALTER TABLE listings ADD COLUMN last_updated ?datatype;"); - database->execute("ALTER TABLE listings ADD COLUMN date TEXT DEFAULT CURRENT_TIMESTAMP;"); // date when first listed // will use ISO8601 string format as follows: YYYY-MM-DD HH:MM:SS.SSS - //database->execute(""); - // For most recent listings: "SELECT * FROM listings ORDER BY date DESC;" - } + } + // cart if(!database->table_exists("cart")) { - // local cart - for a single cart containing a list of product_ids - // public cart - copied to all peers' databases database->execute("CREATE TABLE cart(uuid TEXT NOT NULL PRIMARY KEY, " "user_id TEXT REFERENCES users(monero_address) ON DELETE CASCADE" ");"); - // cart_items (public cart) + // cart_items database->execute("CREATE TABLE cart_item(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " "cart_id TEXT REFERENCES cart(uuid) ON DELETE CASCADE" ");"); database->execute("ALTER TABLE cart_item ADD COLUMN product_id TEXT REFERENCES products(uuid);"); database->execute("ALTER TABLE cart_item ADD COLUMN quantity INTEGER;"); database->execute("ALTER TABLE cart_item ADD COLUMN seller_id TEXT REFERENCES users(monero_address);"); // for a multi-vendor cart, specifying the seller_id is important! - //database->execute("ALTER TABLE cart_item ADD COLUMN item_price numeric;"); // sales_price will be used for the final pricing rather than the retail_price //database->execute("ALTER TABLE cart_item ADD COLUMN item_weight REAL;");//database->execute("CREATE TABLE cart_item(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, cart_id TEXT REFERENCES cart(id), product_id TEXT REFERENCES products(id), item_qty INTEGER, item_price NUMERIC, item_weight REAL);"); database->execute("CREATE UNIQUE INDEX index_cart_item ON cart_item (cart_id, product_id);"); // cart_id and product_id duo MUST be unqiue for each row } + // orders (purchase_orders) if(!database->table_exists("orders")) { // TODO: rename to order_requests or nah? database->execute("CREATE TABLE orders(uuid TEXT NOT NULL PRIMARY KEY);");//database->execute("ALTER TABLE orders ADD COLUMN ?col ?datatype;"); @@ -191,85 +189,6 @@ void neroshop::Backend::initializeDatabase() { //database->execute("ALTER TABLE order_item ADD COLUMN unit_price ?datatype;"); //database->execute("ALTER TABLE order_item ADD COLUMN ?col ?datatype;"); } - // ratings - product_ratings, seller_ratings - if(!database->table_exists("seller_ratings")) { - database->execute("CREATE TABLE seller_ratings(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " - "seller_id TEXT REFERENCES users(monero_address) ON DELETE CASCADE, " - "score INTEGER, " - "user_id TEXT REFERENCES users(monero_address), " - "comments TEXT, signature TEXT" - ");"); - } - if(!database->table_exists("product_ratings")) { - database->execute("CREATE TABLE product_ratings(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " - "product_id TEXT REFERENCES products(uuid) ON DELETE CASCADE, " - "stars INTEGER, " - "user_id TEXT REFERENCES users(monero_address), " - "comments TEXT, signature TEXT" - ");"); - } - // images - if(!database->table_exists("images")) { // TODO: rename to product_images? - database->execute("CREATE TABLE images(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " - "product_id TEXT REFERENCES products(uuid) ON DELETE CASCADE, " - "name TEXT, data BLOB" - ");"); - } - // favorites (wishlists) - if(!database->table_exists("favorites")) { - //database->execute("CREATE TABLE ?tbl(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);"); - //database->execute("ALTER TABLE ?tbl ADD COLUMN user_id TEXT REFERENCES users(monero_address);"); - //database->execute("ALTER TABLE ?tbl ADD COLUMN product_ids integer[];"); - //database->execute("ALTER TABLE ?tbl ADD COLUMN ?col ?datatype;"); - } - // categories, subcategories - // Note: Products can fall under one category and multiple subcategories - if(!database->table_exists("categories")) { // TODO: rename to product_categories? - database->execute("CREATE TABLE categories(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);"); - database->execute("ALTER TABLE categories ADD COLUMN name TEXT;"); - database->execute("ALTER TABLE categories ADD COLUMN description TEXT;"); // alternative names - database->execute("ALTER TABLE categories ADD COLUMN thumbnail TEXT;"); - } - if(!database->table_exists("subcategories")) { // TODO: rename to product_subcategories? - database->execute("CREATE TABLE subcategories(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);"); - database->execute("ALTER TABLE subcategories ADD COLUMN name TEXT;"); - database->execute("ALTER TABLE subcategories ADD COLUMN category_id INTEGER REFERENCES categories(id);"); - database->execute("ALTER TABLE subcategories ADD COLUMN description TEXT;"); - // categories types - int category_id = 0; - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Food & Beverages', 'Grocery', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAACZUlEQVR4nO2aPWgUQRSABy0iokRIdWoTBJtoIVqEgD+NINHCZiWFprCykYDa2MUmimBjCrWyCAouBCwEC7GwUUyTwlILrSL4V0RBRf3CoMKRm73d2503vovvg+lm3sz72Jmdt3fOGYZhGIZhdAEYR47limvIQoML+uaBrnmVeYIAJ5FlQLuAKWEBLe0CpoUFjGgXMCssYL92AXeEBRzXLuChsIDT2gU8FxZwQbuAV8ICZrQL+Cgs4KZaAcB64KewgFyzgCHkeaxZwE75/FnULGBUPn/eaBYwLp8/nzULOEUaBrQKmCINLa0CLpGGEa0CrpOGjooQGP6TuG/XCsZlgfYs0O+e1kqwsCIEJojHrNZKsLAiBA4Tj4t1BSyQho6KENgbMf5YXQEvScNMwRkQg7fAuroCPpCGW4G5t0SKfb5W8h5/SyMNt90qgM0R4voneIOrC/CJNHR8EwAGG8ZcBnbXTt4DvCYNV90qgG0N4r0HDrqmAPOk4URg7kM1Yz0BdjRO3gOcQ55fwHYXvgj9qBjjC3AfOOZiArSAb8ICHnWZ358DY8CVgrFHgF3AxqiJtwPMCQs46kropRiKDrBV8Mvwg4pr+HcCPMCkQPLvvFzXDwI8/kYVMXl/v9jnKqJCgAc4C3xtmLz/pWmP6wE1Ajz+dlXw0aGM78ANYJPrEVUC/gIcAO4CSyXv+BfA5dC7vq8FtAOcKRAw5CLQDwIyyQWaAOwJyGwLCG6xxtgZgB2C2Zo+BPn9P4G8S3saWmDJmLyfBGQI0HR+2azbMAHYE5D971tgtOxAq9Oazi+btWEYhlvbrADFelwIpcui8wAAAABJRU5ErkJggg==') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Electronics', '', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAACO0lEQVR4nO2bTU7DMBCF3yDgFGVBWSNY0ntQDsJBABXBHWgP0u6Q+FkCC3qKIvpYpEShHbeJk9gpmW8VWZN4ZuJxZmwHMNqNVPUgkh0AvZUOREaKbA9AZ6l5KiJjRbavdDcWkamvrrVAsk8Fh+xQER06ZDU0p3ixU9WDthVzQGwFYtN6BxiGYbSa0qkwyRMAfQCHAPZKa5SPLwAfAB5E5DlQn38huUvyjuTcka6GYE7yluRuDAfcRTR8mYGvHV4hwGTYP/reXwNzAKc+4eCbCZ6jOcYDiR3nPjemscMC9TyArk9nNXOkNXLDekJ28ugB0Gpy7U2Hmu2LsO9o12y6ADACrBgyB5gDYisQm3QSXMz2Tfq0VYKIrLXJRkDAvqYAVtb9HWj7BrUQ0gFjEbnII8hkj6Cytf91WAj8XpA8A3C5LJD3rTUV6jtOVyIyAf6GwAECDbvAaDaNAEwACwFzQOsdkJ0DPrEoEf8Zmk2fvxfZVHiCpE7+V2z6ilkIBOyr5/gmq7K1apIhpAM6aGCe0foQSB3AAoectgnHRko6Em0ExFYgNuaA2ArEJvsZHCN/JvhVgy5lmTnaNZvSpblsKjxF/lrgPb9ewXjTGh17mym+ITBCsiXdFObwLOS8HCAiTwDufe6tiVsReQnaI5MjMgOS31Uf9yjAN8kbljgiU8UhqWMkOX4X7i3qqpkhmYceROQ1UJ+GYRiGE9pPU9uJOSC2ArFpvQOqXBYvsp5wjdXqzfUr7Np63jDK8QNj5L+yJWBCUgAAAABJRU5ErkJggg==') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Home, Furniture & Appliances', 'Domestic Goods;Furniture;Home Appliances', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAACoUlEQVR4nO2Yy2oUQRSGKwkqibeFF0SjuPC+EQQvuPJGEEEGldmKlxAUl6KQjQhufAEvoIIuTGBwo75BXAgRdRtcqJgH0BiiRoVPjvSQoadrpipOV1W39UHv6tR/6lD9V9VRKhKJRCKRSCQSmRdAH7APqABVR18l0exVvgC2AqPADP4Q7RFgi+vFDwKzhIPkct7V4s8SLkMutv0s4SK5bc6zAKOEz+M83X6G8JEc+/IowF6Kw548ClChOFTyKECV4lCNBeg0xB3ACf5zD+gGrgI/CZdvwAWgq+MFqAOcDLQIcv4fUS4AhgiPU51YWC9wEDgKbGgz9inh8LBNrpuAY8B+YHHWgEXATWAqNfEYsEMz6TbgN/6R33Fji9vry9T4L8ANYGGjuT1vIfAZ2KkRqOGfEU1uh9u8XWQHd8vAMwYiE8CCDJFD+OeA5lf+aBB7Wga/MBQ6lyHUBbzDHxNZR15yFJowJoOnDQe/0my1K/jjsianN4bxUzL4u4XgrgyxVcAP3COaKzPy2W0xx7QEvLUIuBtQp0hnfvcs5hiXgGsWAV+BJZrjpub4a2p6AMssfmlhWIL6Lc/zQRUowEWLdfwC1tYDn1kEjqtAAV5brONJY+Bx7GgyQ99Ymp8w0BjcY3hxqHNbBYal+b3/ewtsBLhuaYZLVSCIMSc5mTKcNUl/II+bvJkzvzRtHkVlYc780szDDIvIQKsC9FiaYdFoNr80lmZYNJrNT2OGITY9O/F4WqNMAO5TPm4ZLV4AVgCfKNe/v1zZAGwvSRE+SFfYavF1gNXAo4JekOTC8yCraWINsB64JA2R5C0+mSE46bAX0Er/TvIsXvfPC9ehaYfXlCN86yvfCfjWV74T8K2vfCfgW1/5TsC3fiQSiUQiEVUK/gB5u4ODDC6IPAAAAABJRU5ErkJggg==') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Patio & Garden', '', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAD20lEQVR4nO2aT6gVVRzHv7+UMk3RAjErynTRoiBCqAdtcmEiUiFkqxbRrnbiQiLquVKTstxIGOTGzQvJlegiwUUlRJYP+iMYQaWP0pSnkvi093Ex8+h6PWfuPTPnzNyb84EL78098/v9vt8798y5vzNSS0tLS0tLy+2KNV1AJ8AcSaslPSfpKUmPSrpX0lxJFyVNSBqXdEzSUTP7tqFS4wIsB3YDk4TxPfAGcHfTGkoBLAB2AtcChXfzK7C+aT1BACuBXyoK72YMmNe0tp4ALwH/RBY/w3HgwX5rqX0SBF6UtF/SrIJhVyV9Iem4pL8knZW0UNmkOJK/is4/KelZMzsXo+ZokF32RZ/8b8BrwPwecRYD7wDnC2J9zSBNjsB84JSn2GlgKzA3MOYS4ECBCe+n0hMMsMNT5BTwaoW4BmzzxL4OPB1TR9kiH86FunglUo6PPPG/jBG/anG7PMXtjphjNvCVJ88zsfKUKewu3JPVBJEnKeBJ4F9Hrn0x84QWtdbzqbyVKN/njlzngaLbZjqA9xwFTQGLEuV7wWP4Stf4O1IU0YUr8biZXUiU74ik647jzrtBHQYscxw7liqZmV2W9LPjraWu8XUY8Ijj2Juey7QMZ4DNXfH/cORc4iouyADgceAg8BPwIXBPyPmJuF/SVuDljmNTjnGzXSc7D7ogu5celrQgP/RY/lrTb4zErJX0Wf6367fERddJfV0BwIhuFj8TcEtAganp7AOscLzvnHR7XgG5+EO6VfzzZpZsMisLsEzSQ463TrjGFxrgES9JYwHiN/Q5riozE58v3zdB0YAHKP69PVqp3AQAd5L1B7tx3RZ7Btvcxy1ooEwANnnqDF92dxkwCawHLoea0IeJsTiBu9t0lYAeYWfhS8m+ApNkc4GAdz3JvSYkkRrGB8HiO4ofIRef/z8POO1J5DShNpluzgH3lTbAI+j1goTbBsiAabIOdFyAWcB4QeLRrvFNccuHEdOEVf0mr0Opg4+BtHsewKEeRYw2YMBMez39hg/wBFnbuYjR5JL/429gXXLhXSbsqVFgL8bKaKjaEHlb0qWKMRqlkgFm9qek8guNASBGS2y7pN8jxGmEygaY2RUNVmMkiFhN0U8lfRcpVq1EMcDMpiVtihGrbqK1xc3siLK+4VARe19go9y7MgNLVAPM7EdJe2PGTE2KnaGhWhxFN2DYFkep9ga3y70/N3AkMSBfHA1Ux9hHyt3hoVgcJTNgWBZHSZ8PyBdHEylzdHC6zEl1PCCxq4YcVyR9UubEWh6WBjYoe44gxQMVZyTtMbMfEsRuaWlp+X9zA8EbEeUfOYl4AAAAAElFTkSuQmCC') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Digital Goods', '', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAADS0lEQVR4nO2au2sUURSHJ7Exia9SRURJRA2oENFNQLcUFXQ3ypYSNBZaqcFCUCSinfgfmMZkjaQSQTvFJ9qorYiFj8JnhEACRtFPDrmRzc25szNj2Mks94Ot5t7fnPkx9+ycc28QeDwej8fj8VQBKKEQMr4BKAIjwHtgEvgEPAT6gMUhc2WOzYhjrEYpSNMAYC3wjHC+AN11ZwCw0TxcFP4Ax+vGAKAFeEM8fgH5ejHgHMl4ITkj0wYwlfQ+OF7zIeAIcBEYcwTdmXUD2h3B9Fs6HcBPZdz5rBuwxxHMckXrsTJuIOsGlMKuW1qhD+gNwL8BI34JzMbngGCeJ8GCI5gWReuOMm4o60kw5whmRsEDLANGlXGXs25AEzCuDJESuBtYAmwB7juCPpBpAwTzyZuEb5VLJcsGtAE/EhhwwtLJpgECcCjmw98EGoN6MUAAeiK+CdeAhYFF5g0QgFZgUEmMv4EnwN7AwXw1YJUxYcYvwjz5d9gO7Ad2atWhMqdLuVeXY+ysmCTWpM/p8Xg8sTBJrtMUQ3lgxX9orTQaBVNbNEWYk04SBNYBZWBC6QI/BfbF0CqYnSSZW8mE+SttC5lbm7/BSoDDZq+vGmXtQ8d6e4Yj6MhHVc+8MICpr7w4SO2/QNFpBG7F1DqaqgFMvfZJip1TitbpBDpy79Y0DSiTjFGr3F0EfE+oNZiKAUCzkvCmGx5F0/DYDNxzBHWwWl0B3AU2Ga2i0bYZr/x3qKUBOcfNita4pabBEdbyuqJc/ypzLS3pJGlsS8OAwhw2PbWldFvRke12jUIaBpS0O6W99eUN0PFvQOCXwByDzwHsjnEAQnp+Nlcrrg8o1x85qkONXWnkgHbHzS5Y47aak19hR2D6letybKbD0pIzRRob0jCgwZz41LgO9AKXQg5B5aymp8aY0egNqRLfWifKamOAAJwlGc+toKUSfJlQ68y0ThoGNAOvYwYsy2GHopV3LJUwXtldopoaIMj6Az5HDFg2QY4FDuSYrNIFciGF0XpFo7YGCMAaR6a3A/73ze7CFDzVDJVjdasd82tvQEVSlN2eG8A70yL7aPb/T0rNH0REjs5L0wR4YIybNMluuFpvMTUDPB6Px+PxBFnnL5kjkrLcntRPAAAAAElFTkSuQmCC') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Services', 'Non-product services, Freelancing, etc.', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAADjUlEQVR4nO2aS6hNURjH/+t61c2juCjKsy5loCiuiTKiFGUiTEQxo0gGCteEiYmZPGbUjQkhRhQDEiZInYG8out6XFeKe/kZ7H1qO/fsx7l7rb3Ocfdvck77nG+t7/+tb639rbW3VFJSUjKKMb4dkCRgk6T1kiqSThljfnh2qTiALfzLZd8+FQpwrSYAQ8Ak3345B5gHHAR6Gc5pYLVvH50ATAPOA4N1hNfyAOjy7XMugA6gM/y+AnifQXiUQeBAaD8DWOhXUQMAe4CfoZDnwECD4qM8BP6E368DE3zrS4Qg1X/lEJzGDht+ttloJIapksY5bH+GjUacBcAYU5F0N+PfK5KuSHog6XeG/w9Iav56AZgC3ElI4wFgZ41NJ/AkwaYfWO5LU8MANxudx8Bs4HOMzRAwpWgdIwZ4FyOkkmJ3PCFwq2z553IRrNIRc/15it2zhN+mj9CXYRQRgO8x19NEzEz4bWCEvhQPQQETN5c7Y2zagEcJU2CuLf+KyIC4VB8jqQeYE70ItEk6KWlZjN0XSR/suecQoDthFKt8DRe8bcD+lJGvch+Y6FtfIsDMMM1dsduGny6nQLuCNHfFZBuNuCyFX0q6HrlEziaj9p8k9eRsT5LjQ1GCLetWBbe0G5I2Sjo2gqbuStouaZ2kSZIuGmPe2PKzUIANZD8UGQROAON9+20VoB3Yy7+HHFHeAqeABb59dQ71d4vWSt00iiiE0qg9M3hhjPnoxRMfhNPhAsE+/yGw1LdPLQ2wBLgC9AGvgLNA3I70/wLoIiita3kKtNezsV4HhPf+TkmzZKFaM8Zcythvl6RbCX3uMsacyetPkgNrgMvkO/sfRsa+u8I1JInT9WzHWhA+S9I5BVVa4WQY+Sp9LjpfTlC0uOJnSv+rMow8BMXWStvis6RdXmLPDckuHuBQK4oH6LYg/miriq8Aw+Y1nsU30nkeHgHzixCfuQ4geBhxU/nv7b2S7qn+M8D3km5LumqM+ZOj/25jjL3RbzDyaSxy3H/Tp/3iZhKfOAWwl/ZRPirYAmd5DC5JazP239Rp75oj1oSPNvFxJ0K/lD1FfXLUGFO3WMoNQZ0f95JCM2A37VssCO7FR4LQbOvB4cLEN1kQXgObbWtzUQp/k7Qv/LTBkKQ3kh7XlseFQ/qa0E+rv9ycRkIQ/n/xVeoEYfSIrxIJwugTX4Xg7mDtpcWSkpKSkoL5C2IZ98cgmOE6AAAAAElFTkSuQmCC') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Books', '', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAACCklEQVR4nO2bPWsUURhGz00iWlgYFAtbQRFUgiCI2NjZJgEbSZlOsNTKP2EnNmkCaZLCzkL8HYpg4QeSEAJiEVEeC7dY1M3c3XnnPpPde6plZ/flzNll7sDehcpskyZ5k6Ql4CpwHjgRahTPTkrp7aiDC7lTJCVgDXgKXAwQK8U7oF0ASaeADeB+kFRvmMt83Qum8OQhI4CkZeBBARcLOd+AJ51bGDkygKQLwM1CLhaavgGXmHCpPC40BVgsYmGkKcBUf/owxo1QBu+Bg8B5TSwA18hfykcOieAbcDml9CtoXhaStoHlNjNa1RvisPTJD/jedkBUgGNLDeAWcFMDBM1x3S+09o9aBs9Keg7sB83LYR6413ZI5I3QeuCsYtRrgFvATQ3gFnBTA7gF3NQAbgE3NYBbwE0N4BZwUwO4BdzUAG4BNzWAW8BNDeAWcFMDuAXc1ABuATc1gFvAzcwHaPPb4E/+7A3qOz8mfqekFf3LlqTbkuYDJfvJfwI8dDsV5a8AL90+XTDORXCzMwsjTQEOhx7vdSnioinAx6HH17sU6SWS5iR9HlwDPkg67XYqjqTHQxfCV5LOuJ0iadzeJukk8Aa4NXjqC/AMeA3sdqcWxteU0sg9xVn7+ySdA3aAO1FWBVlNKW2POpi1DKaU9oC7wCPgU5BYLxh7h+fgH6Q3gCtMwV9nK7POb7zRpspIHJDQAAAAAElFTkSuQmCC') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Movies & TV Shows', '', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAC7ElEQVR4nO2az2+MQRjHv09pohHclBIkUhc/Dhqk6iYSN0LqVxxxpPEPkHB0QURE4w/g5CROIkSJgyoJ4kaiKRJpKyG0/Ti8u0mzZrbv7nR3urvzOT7vPLPf7zM7M/vujJRINAyAAT2xdUShYP4GMAUci62nrswyX2QKOB5bVy6AbuBSQL4Bt/ifP8Ch+dQ67wAngYmC4DNV5PvMFxkBFtdCexBAB3C1ROwvYFsFfZR+7Ut5D3TV0kfVAIMe0W+Ajhz5c438O2BVPbxUBdAJjHrE35wjt3FHfjbAfmDGY8K5jTWN+SLAFY+RH8CGkrbNZV6SgHZgyGPoBdBeaNd85osAG4Fxj7HLTW2+CHDCY24aeFDG/MJe7SsBuFPGaLSRt5ziV0g6LemgpG5JK2spKoAxSR8l3Zd028zGg3sEjgLfKxy9hcA3oD/U/Dn8e3kjMAOcLefROwWAvZIeSloUVMX4TEvaZ2aPXA+dBQDaJA1L2lpDYfXktaTtZjZT+sBXgD2SnjgeTUq6JumtssrWg9XKFuAtgf30mdmzXC2Bi4759BfYESiiKoAlZG+SIVxw9d3m+cz1jthzM3s5f7byY2a/JQ0GdrPOFfQVYKkjNhooIJQvrqA5kHTP0XSZK99XgJYhFSC2gNi0fAEW3l/KFQLcdYR78+Y3fAEkBb3wtPwUSAWILSA2zbAGuH719Upamye54QtgZkdKY4WdIdfi2PJTIBUgtoDYtHwBGn4RBAjJb/lvQCpAbAGxSQWILSA2qQCxBcTGV4BJRyz2NZU1gfkTrqCvAJ8dsV3AzkARVUF2ufJUYDefXEHf4WifpKeORz8lXZc0ovodjnYpOxzdHNjPbjMbKg2WOx5/JSn33d4FzrCkHtfxuHMKFBoOqH6jXEumJQ24zEtldoHCjYrzkoJeNiKDMvOPq+8B+skuHDUaX4HDc/nLe01uubKF6ICkTZI6q65obRmT9EHZNblBM3NufYlEIpFIJBKS9A+F5c3zqqADtAAAAABJRU5ErkJggg==') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Music & Vinyl', 'Musical instruments', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAFHUlEQVR4nO2bXYhVVRTHfzuiJBuNMc2ERDJ0irEilF4sDaIPeopAjaCnihF6k0CUEqLGeQoVfEh7CsqH8CnNqBCCCgqJzI9yCMf8wjKFGY0+EH897Gtex3POPV/3XsH5w8DM3mevtf777LP2WmvvgQlMYAITuI4ROqVInQH0A/OB2UAvcCsgcB44AxwDhoG9IYQznbKtLVBvUJeqm9T9FsPFxpgN6hK1Yy+qMtRe9Q3114KkszCirlF7u80vFeoUdUgdq5H4eIypg+qUbvO9Aurz6sk2Eh+PE+qybvNG7VE/7CDx8diu3tYt8vPV4S6Sv4RD6txOk1+o/tZl4s04pT5Uhkvh7UVdBOwm7uHXEsaAx0II3xcZVGgC1HuAr4A7iozrIE4Di0MIw3kH3JD3QbUH2En3ye8EhlL6pgMfN2ytF+q2bn7kDexQb27YM6BeSHluW93kV3SMYjr+J99k10DG8/XECcYI70RHKKbjKvJN9q1PGXPCHBFjHh+wBphVdOJqRi8wdXxjY1IWpIyZBayupNWY2LQzti+CEbWvmbxxZWRhzBYJ1I0t5uBVoG6POgrsAg4AxxttdwEPAE9k6JsD7FIfbsjYDjzTQlcPsBJ4u7CVxnz+SI1v8LD6gnpThs6p6ir1aIacb2z95psxYpl6grGYURc2m0E8Qfdk9d0a9S8pMwGbalK+qrDyyzasrcmGDWWUFy1jJWFzWfJNdmypwY79afITvw1jAfNUWn9OjAB9IYR/K8hAnQz8RHSUpcUA05MKrWlxQD/VK8avVyUPEEL4E9hYVQxwf1JH2gTMr6hwFPioooxmvAecqyijL6kxbQLmVFT2aau3ry5QNzZ++rOeDSGMAp9VtGl2UmNaIFS16rovq1NdAHwHTGo0vaIuCiGkOivgB+C5CjZdFUpD+gqoGv2dbNH/MpfJ0/j9pYoyWyGRU+6CSEG0cqDmbCsisxTSJmCsotxW2eNW4O+mv/8iOros3FnJonj+eBXSfMBoRWUPZnWGEPYbi6uXlv3WEMKBFjITt7ECyM9JXVkx8hpTE51OGRhT36pp+UCS7LRP4OeKNvfQ2qkVwXKqO+ZDSY1pofA0Yom5iuM5BtzbiORKQ51END5xH88rBpgZQvh9fEfiCmjEzAcrKIQYu79TUQbAJqqRBziYRB6yt8EvKiqFGOCsLTtYXU2MGapidxnlSyo6nWZsMWZ1eXVPUrfWqH9pmQkIxnJSXuwwlqvScNRY7krdHYze/kXrvV1yRE1d6ZlOzrh838oxXzuJcfpU4Fuyk6lzxMRmL9FRBqK/6Aeeov4i7LoQwpulRpqvLH7FoYXaZ7GV0060LIvnmYTBDAWJJzbqDLM/h05hsBW/PMnQEOmZ2L4Qwj8J7aPA2Ryy24mTwPpaJKnLMmZ5YNyzeU5sOoEVtZBvIpZ2PH7BxiR47ZDPfTyeO9Q1XjrYA8xLeWSIeFDZ6riq3RgGFoYQctUQi16RuRv4GphZwrBO4A/gkRBC7mSuUEUohHCY+IarFkzagXPA00XIQ4mSWOMW1mKq1+jqxFngyRDCno5pVOcaLyl2G4fUNL/U9knoUT/oIvn31e7fVzTGCZ28R3RcXd5t3lfAeJlq0PZeqTmvrlNv6TbfVBgTqDXWmxD9or6m3l63vW37VxTjtZRHgWeBx4H7CugT+BH4HPgE+DKEcLEddnbyn6amES9CzSPm/9O4fOH6PHErO0qM5PaFEE53yrYJTGACE7hu8R+yRA2BiW4OUQAAAABJRU5ErkJggg==') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Apparel', 'Clothing, Shoes and Accessories; Jewelry and Watches; Fashion', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAACXBIWXMAAAsTAAALEwEAmpwYAAABhklEQVR4nO3av0rDUBSA8dBF7DP4B1wERxF8kD6HQlEonZrRVxDBTaFdXH0NDQ5uuluJ0k30kwsJ1JDatMk9p17Pbyq0cO7HTW5LSRQZY4wx5s8BtoFj4BZ4BCb4M8lmuFlHwJZk6CZwDnyg5xMYATu+Yzued3JRbi0dX7F94IvV49bUbzo2XnIxD8D6AnPWgLslZ51px+YugFaFOS3gknpi7djcFdD+ZU4buKYZsXZs7gk4AfbcZZ5FutenwDPNirVjNVS7pwOJrRZNWLG58migS7i6ZcFjwjUuC04IV1IWfACkhCd1bbPu4/3ALu0UOJx3UleJHqCvVzu2YvQg+4yqbA292rFzogdT76uaWkevdmzhIEuy8B/fZSgr+Q3xCtzPPKDqWqVgEViwLNth31DmPbDIgoVF0lBmwb5hOyzL+44WCfdZcCQN22FZtsO+ocx7YJEFC4uk8Q+D3xV7U43gG8XgoUbwbvbXqLQXYEM8eOqpPPdE3JtAqJsxVIs1xhhjTFTXN9+cDWs9QZG1AAAAAElFTkSuQmCC') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Pets', 'Domesticated Animals', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAEcUlEQVR4nO2a3YsVZRzHv4/HsjfbLLctaMNqgzapC7Oydwgh0kuTqLvQiqD6A4reichujW6KbmqXrbQwNuyii7rpwlXXtDKLCs1Aio1W18yV/XQxM3Ac5zzzO8955pyF5gPD4Tzzez9nnteRampqampqamoiAThgAzAJnAD2AI8BC9qwsQB4PNU9AXwDbARclbFHAdhEMe9ZigA0gJEWNjZ1I4dggHtaBJ7xjMHGcx79OeDubuQSBDBeUoDjwBUe/UHgnxIbn3YzJzPAecBsSfAAL3hsvGTQPwmc283cTAC3GoIH+M5j4wejjZWx4jb3zAYuNcpdB1ycb0zbrjXa6DdHVULMAlhtOUnDBe3D6T0LC41ypcQswJ9tyJ7xD5C0tA39qTZkvcQswPeSMMqeKmibM+oiqWU/0i7RCuCcm5J0wCj+R0HbEaPufufcX0bZUmL+AyRpzCBzUtK+gvZ9kmYj+egNJBOZ4yVD2DaPfkcTqUpJk3seGAXeAG5pIfesJ4E54C6Pj6CpNLAqjWkkjXEwVt6ZgzXA0YKA3gHOzsk2SBY+Rbxm8GVeTAGLgHcLZKeB+2MlP9gi+YwPyS1TSZazGzl9SfyI0V+2nM6WwrvT7/nkHbDVE9dRYjwunl+kmQ0dO2o/rkcNcb0ew9G3BkeHgGizM0NMC4HfDHHtjeGsrFfPWN2m3QHgvvQaaFN3tTGmY2W2LPMA6wztTosQsAz4SNJhSdvT6zDwAXCl0Zd1U6Q0dksBDhqdlQ49wB2SJiStk9RoutWQtF7SBHBbDF8ppbFbCvCl0ZnXFnCDpHFJl3jE+iV9BizvxFcTX5UJWAy9Jdsi5+dWN0h2cMYk9RnsXCRpDDgnxFezWyWxdw6wzdDh3OTRf9nYaTXzosfeSoP+1ijJpw6XAj95nG336F4OzAQU4Bie0QH43KN7APA9akFFGCI5oMizC2i5RQW8GpB8xiseu/0ks8Q8k8A11rzaOmkhmew8IOnetOlrSSPOuX9byPcpeV6LdoAsTEm62jn3dwv7iyQ9LCkbOb6QtMU5V7Th0n0Ie/bztOwL5jUkz/50hAJMA5dVFWfsHSFJEnCWpFFJiyOYWyxpC7ll97wGeDPCL59nc6/zKoVkM2RzBclnvE0XV51tAfQBn1SYfMbHJKPL/AFYCxzsQvIZvwPrep23gCXA+11MPM8IsKRXyS8n2QnqNYeA60PzCHrnBrhA0m5JQ6GOI/OjpBXOudIdoDyh84CHNH+Sl5Jj9QdDFEMLsCpQr0osO0lnEFqARrlI1wmKKbQAewL1qmQyRCm0ExxQ0vHEmOvHYFrSkHOu6NjdS9A/wDl3RNLTIboV8VRI8h0DPInt1biqmAWe6HriuSLcDkz0IPkd2M4QqofkpHY9yf5g1exMfUV5cTr629fAsJJ9ujWSblTnr7SdUjLqjEsadc7t79DeaVT6+jnJlPlmSSskXZVeyySdL+nC9FOSZpT05DOSfpH0a/q5U9IO59xMlXHW1NTU1NTU/D/5D8Q7H3ts84ozAAAAAElFTkSuQmCC') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Toys & Games', '', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAEAklEQVR4nO2aS2hdRRyHv0lrsb7ahQk2ol1119YWQaUgCq31QYUq1ErBR0QFBSm4EcWF4EY3KiotIhUfuyAUBB/YjeJCSx+SpO1CUYwLH6W2xi5iG5PPxbmhye3MfZx7bk6Se7/NJTP/md9/frlnZu6ZgS5dunTpYELehuo64PHKn++GEI7ViH0Q2AL8DLwVQjibV3deoK5Tx73AuLo2EfuCszmoLp3rnAtFfdOLeSMR+1skdtNc55yiJ2e7ayJluyMDFVgVib02p27h5DVg0ZDXgKkWdSdbbF8YeQ0YbkFTYKSF9uWjXlmZzZtlSn2p7Pxn0so+YClwM9BfKboFeDYS+kDlcxIYCSH8mFdzXqPuSKwC85qOXwUaegTUFcATwHZgDdCXU+8U8BPwDbAf+DaEML+/JepO9VSOCa8RflCfUpeXPc4o6u7KzN1uflHvK3u8s1A3q//NweBn8rm6puyxo/aow3M8+GnOqtvLNuDWkgY/zZT6ipp7n9IoqWVwc7uF6xCA54B96pJ2CqUMWN1O0SYYAPbbxlUiZcDl7RLMwb3AZ+pV7eh8oewEbwcOqLGXKy2xUAwAuAkYUrcV2elCMgCgF/jE7J1kbxEdLjQDIFshngFG1b3qFvWyVjq7CHUQ2JG30xI4DxwGvgY+DiEcbbThQvwGxFgGbAKeB46oX6k3NtJwsRhQzW3AQfXFervJxWoAwBLgZeDtWkGL2YBpnlafTFV2ggEAr6pXxCo6xYCVwP2xik4xAGBjrLCTDOiPFXaSAdHlsJMMiNI1oOwEyqZrQNkJlE3HG5DnutoYsAc4RnZZahfQ0E/PHAwDHwB/AGvJDmivbpPWBdTBxIHFiHpdVWwwfm2uVfaol1Rp9VVyyMNgqwZMqDck4pepQzkTizFk1eBnaG0035ll1IBm5oBDIYShWEUI4TzZV7Uo3g8hTCS0vid7/VUIzRjwd536M60k0mRfp4sSSk2C/0TK1qs9IYTUHcHY4zEGfFknh63AiqqyDalgtQdYH6k6DpyoofNdnTxmiexMPEePJuL71bFGn7uqtrH5ZszEKZA6kMituLfYaq/6b0RkXH248l+Yjl2vnkgkNdCA1mOJtsfNruRPx/Woj9TIq9jlUX0vkZjqqPqpelSdTMT8qV7agM5y9WSij0n1SEXr1xr57Ct08JXEVql/1RCtx64mtB5qQeeM2p7b5+o96rkcSe3NofVODp1z6t3tGPvMxLZVXG6EKfU1Z8wRTej0qK/b+K200xZ8UlwrudXqR9begR1Stxagdad6uIbOhPqhen0RY2vqEpLZ0nQX2TrcR7Y5GgUOVHZohWB2nLUBuIPsus5K4CTZj6MvQgi/F6XVpUuXLh3N/4LZQfQlM+IfAAAAAElFTkSuQmCC') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Baby', '', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAD9UlEQVR4nO2bS4gVRxSG//IxzvhYZaNGxpnJJghCBBdCdi4iIRsNqLjQvYgEAllkJbjwAQkJqItsgskQJIIJYjDim8EgQUEQjeAwhBkFRUVdRGKI5nNR3Vpz0923H9WPq/0t+9Y9db7TVX2rq/tKLS0tLW8wpu4EfAEYSR9J+kDSW5ImJB0yxtyoNbEqABYBv/F/ngG7gRl151gawBJgPELeZXfdeeYG2ARMAA+APcAc57PBFPLhSHi3To9cAJ8A/3XIXAc+B/YCj1LIh+yI6qPWiyD2wrVC0rCkxZKQdEfSJUnrJH0lfzmOGmO2dB6c5Sl4JoBhSZ9JWitpUUXdPoo6WGkBgH5JuyRtk9RXZd+STlTc33SAxcDvGeasT8aC6Vab/AgwWZP8OLCwTvmlwJ81yd8EliTlV+qwAEYknZM0WGY/MTyUtMIYM5XUqLQlYs3yknSgm7xUUgEaIC9Jd9M08l4A7G983fKStJkUN0FeCxDIn1f98pK0StLWbo28FaBh8iGruzXwUoAGDftOrnVrUPhn0JFfWjSWZ65Ket8Y81dSo0IjABiUdEbNk78haU03eanACACGZOd80+SfSBo2xtxP0zjXCAjO/Fk1T16S5knqT9s4cwGCMz8mu4nRVFambZipAIF8VRe8xwW+m3qTJXUBHPmhPBll5EdJI5Iu5Py+3xUudvd1oqJb2J+B2UG/c4FTOWJ87FN+iOru548BfR39DwC/Zozzni/5KjczbgEDMXnMAY6mjHMbH9tfQD9wpSTZOL4h5g4OmA0cThFjf2H5oMOdparG8x0wMyanmcBownefApl+oeKqvUDS9hx1y8pPkkY7jm2R9APBhdDFGPNc0r2EePuMMZOFswLWlX+iOYId1jOAgxGf/4J9juDmtSsh3kWc54ZFC7DHu+50juCcYezQ/j6i3XGCCyPwRUK8ScDfEybgW+/Kr5gmn6IIp4GvE+JNYfcg/QHs9+/9kjFgfky/cdMhjingHa/yQSKflmHucAaYG9N33EjoxP+Zd5JY5ln4n4hj3YrwRy3yThJ51uBR3ASGsWv8TiKnA8lX+3KGfUQSy4EnBeXHgbeDeH1EL2enjQTgy9rlnWQ2YN+vKSTvxEssQqPknaQ35yjCU+xucVS8uCLcapy8k/RG4N+MRThOzMoMuwKMuiY0T95Juo4iNEM+hHzT4SgdmxxOvG4rvObIh+BpJGBfYe0t+ZCiRehp+RDyT4feG/ZxkG8kvB7yIZ6K0JvyIQWL0NvyITmL8HrIhwDrSX8DdZmY5XJPg72LPJkgfh/7vn/VL0tHUtqboth/aHwo+xh9QPZ/ABclnTfG/F1Wvy0tLS0tGXgBtI9sAulPU94AAAAASUVORK5CYII=') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Arts, Crafts, Sewing & Party Supplies', 'DIY & Handmade', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAADZ0lEQVR4nO2aSWgUQRSGyxh3AwETxA2CuIBIiIoyQXDBCCGgKCQXRTEXEdccFA/iIXqIS+LFgzuCKIpiwIsQEAUJKBrNQcQFBBUVRUUFFfdPKtOEztg10z1d1VNt+oM6TA31/qrX1bW810IkJCQkJAQDKAM2ASedshEYJSICGAZUOaU4Kt0egAbgE//yEagXhgFWA+9cuq+A+aZ1ewAWA79QI/9bJAwBLAf+eOi+Nz4DgQHAA3Jz35D+QOCpS+c58N31e4MJ3V6ASvwzXWgGqHXZb3Pqql11R3Vr9gFYGsABS4RmgL0u++udunJX3XHdmn0AFgRwwFyhGeC6y75cBA8At111W3Vr9gEYAXz2MfjXwGChEWAQ8DWL5k9ggk5NT4DdPhzQJDQDzMmheUG3ZrYncTFHZ5qFZoAtOTTn6dbMtR2uAe4o9mS5VRUJjQDnsgy+W6dWIIBTik7VaNaRe76KRp1agZBHUEWnzmjUGJtl8G/lvUCXVr6vwyOPjskVu1STRn0WB7To0AgFsF3RuXWa7O/Pcu+o0KERCmA08MOjg7c02b9W0K3PD0C7opOVIe0WKa7eRk6beQPUKTrZGtLuNIXdLmETpJ/UM4+OvpGHp5DBDy9WCtsAmhWdXRbC5kEPey913zW0IC8jimjRpRA2b3rY2yFsBehQ3NTGaLoByt9lwlZIB0y92JaHrRkedsxGfcIi301n4cvkYR621ureViMBaFXMglRAO8cy2neIOABMVVyTjwS0053Rvk7EBaDTwwHyRDfcZ/uhGcfrx7pjDEYBGhWvwSqf7d3h7t4ocGwgnbv74OGAqz7bb3a1kXZGirgBHHKm8V3ghBPXW+izbRPwxFlL9ok4ApSEPbLKJ+933UiwGaDCiR+ukBkc4DBw3imnnd8tMsHp5ACnyJ1AxBnSHy/IRMo98kO+/13ALmB2LLZB0uGxnT7T6EGRKbc2YKKwDWC8zM4C3zDPbycEN9mGgRc7T/wL0SM/jtgDDClkAKSTwnMDGBf14CcpYoCF4kVkOQLSn8jZNHj3hak8Cgdcxl7Omh58LfZTY9IBV7CfdlODL1XkAG1DnkVKTDigmvhQZcIBs1wXGNvLTO0OSOjvACkLprbfkooy7WUjDYkDdEMyA+j3r0CqXy+CCQkJCeI/5C+Xr1Nj9eUFLAAAAABJRU5ErkJggg==') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Stationery & Office Supplies', '', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAACvklEQVR4nO2bPWtUQRiFn1dFiwiCKPiJX72g1a6ton/AGK0sBEvBRrEVLVXQSv+AmgSLWAqmTCqRpDCCQSRisAhiuoh6LHYDIe7d+biT3N2985R33znzzmHncHf2XshkMpkaY6mEJF0EXpvZSgKtvcAV4BQwFDD0O/AWmDCzP2X78EbSBUm/JT1LoDUiaVnleC/peIq1+TR8QtLSmsmvl9BaNTIF85J2pVxrp4aHJM2sm3hF0pkILZM0l2jxq9zdiHWvbfhlwcTfJB0I1DuZePGS9ME175Z4C7gFXCr4bD8wLml7gN6xEr0U4cyBKAMknQPuO8qaQEgohpiVTDPYAElHgefAVo/yqyoRipvBtpBiSUPABLAnYNgTSbNmNhXUWXceAtMJ9dy0Q+9FZBgtSjro0B8O0BtOta6QLXAbGImcZx+tUNwROX7D8DKgHXr3Ss7VAJ6W1EiO04DA0HPRc6HoE4JFofcRmOkybjdwtsP1x5KmzazbWBcNSV6FZjZWYh4oCKElSUcc40zSK98QCwxBb1zri70TvGNmX7oVmJmAa5H6m0asAT98iszMq65KyvwWGAiyAVU3kJAx64Br0CAZEEU2oOoGqqb2BgSdB/Q4TUmj6y+aWdGxHTBYBhwCgs8Jar8FsgFVN1A1/ZoBU8DXFEL9asCj0gcdbWq/BbIBVTdQNbU3oF9DcNTjvBMA15lA7b8B2YCqG6ia2hvQryHYiWlazw0EMUgGLMTcHtd+C2QDqm6gagYpAw53+tvdlQuDZEAD+O9UGMcT8XkLRI672enrVpJfifW8NGMNaEaO68bnDdCcdxX00haYBeYSazpvjHrGgPYzRTeAVK+6fAIeuIp6xgAAM3tD612hnyWl3gHnzWzZVeiTAUmOn9exUPSBmY1JmgQuA6eBnQG6i8AkrZem/pZrMZPJZGrAP+s7Gd91ZI+yAAAAAElFTkSuQmCC') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Tools & Home Improvement', '', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAABXUlEQVR4nO3ZS0oDQRSF4WtwB451Az424QIEwQX4GOoiIg5EJ0EXYISMegO6EjfgRB05iRPRX4q0EIhCNanursf5oCcZ1T251VT1NRMRERGZAwyAa+CN+Lk1Xrk1WyjACek5ChnAPekZhwygIj2VAgiFxDsAOAUugO1SA6jq376BW2C11AB+3ZQewFej7UB+ATjD0gOYlB5ApQBKOQoToAOOSc9hyAAG9RXzlfi9AJfz1+GlA0idAkAdUGkLLNI7wGIBrAFnwF29X0M/z0sdhdsE7APvdG8YQ/G7wGcPxbvr8Fbfxa8AT/Rj1GvxDrDT0z8/avxJrA3A3j+LbOMlOAHOgU2LBXDwV/VWChQA6gC0BRZZ7oAN4BH4oKv5fkyYFd/tfD8mwLTz+X5M8BfPdTUkBeBPHWA5Qh3gTR1gOUId4E0dYDlCR2Eems73swKsMwth6jvfFxEREbEO/ADiFbekRtGUMAAAAABJRU5ErkJggg==') RETURNING id;"); // Hardware - Heating, cooling, flooring, paint, etc. - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Motor Vehicles, Automotive Parts & Accessories', 'Auto, Tires & Industrial', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFjElEQVR4nO2ba4hVVRSAj1ia2mvGLMseakX0I7LQ+tGP/gVSSY9JA6UyzXLCAqnwkRmlZkUQURYJzWgjRlYaCSVB6WQhlNjLmXLKXhBlTS9LM535YjHr3k7Hvc/ed99z7r0D94P7a52z7tr77r32WmuvG0V16tSpUyc7gOHAZOBRYBXwItAGzALGAsOAa4AHgBaVrwGagTOBo4GrgOX6fivwEDBJZFGtQp/xzwN/8x8HgCeB04BTgKeBfTH5IeA54AyduMeBP7Dzuz4zPKoVgAHA3cD+hLGfARfoM7cAfyXk3wIXq/xqoBt/fgaaqj32CBgMvGQw8HVd6ufp8k7yDjBCdSwmjF7ZRtUc/CDgNYNhHwELgQ8thn8AHKs6llI+y6s1Ac8EGNsDnKvvi1PMitsqPfgbyjB2O3CpwWeUgzjbCZUa/MnAL2UaLPs3az4Vn1SJCVgdYNw/Ae98DszTzy7PdxbkPfhxuo9N/Am8a5FdCWwtYfDr4kGPBkem0ybJb8AJeU7AOsOXfgPcDBwDrDTIt+m7DcBuj0FslhPGcups8Xh/WV6DH62RW5LZKh9hcWxTVC5xwa8eAY71FwRO9AiYRD4sjwl40PBle+VM1zB3vUEuzvIofX8mGRxnmjO4mJlHuLvb8EWS5CzS/W+iLabD5QM6gIEetgzUZ9Noz3oCJgR694Pyq+oKsTnP/20lT3uaPY7ZU7OcgEWUxw4P7+2d6qrDlcwwjVuznIB28qUlwCapFaSxIavBH5nI4U1haLnR3uQAu6Y4dP4kviuLCRhv+YIejQqvsMibNO53IUdrY4BdDepj0jg7iwmYbvnVC1ndVMughupe3egw8v0ybJPUOtOVdRhaj0uyKyZfYpDvjMnnZL3/Y7qlXpjGfaG6i1hi8E0OI4oOSGt4adwVBQLc49C9JlR3EUuC82xM/oZB/kRMbqoaxZkYBQJc7tC9OVR3EaDLoPhhlQ2xyBfG3t/mMHJcFIgUXR26O0N1F7EkHwuASzRnN7Ffg6dBKc8UGBuVV4pPY0+o7iKGcnah+uIKbdGYXRKmNILzd81A09gbqruIJQXOksNy/xLL8mkcDNVdpD4BGLeAa4l/VcIKqPkt0O1wcl8Y5PP0MvN7jwmoeSfY5TjmttvqchLjA1/392NwqyPQedMgXxGTb6piIPR2XpXgDTG5XG8n2VhCvJ5nKNyWVzK0MyY33e5+4pBnlQytqkQyND0l3W2wVIukSeJ+YCRwXX9Phy+0KJ+qTRBpHNCLjjSkqNEQYFejR5B2Vp4lsV6yI6Qkdr1D555MSmIVKoq2Rtlf0q4vVacV4F7Hl31Z5gTkURaf5auvnMJor0aEp1u2hJwAr3pmjs0l2HO7Q5fYMspXn+/VmOlXXuuoHK2MhawfO4zuLOFqTJ7NtxKURBsbTZefQ1R+p0Euy3RoCW01szO6HJ0RZQ19zYymOvyNKh9puR7v0PtBudr+wWF4d6F9zmLDSR7tOflcjwva1prkvZh8RYph+/RocrHF0iAx2PM0WhLlBXC+xaFdFlslIf1ASV4WT5/w+q94nib5ttFiPn+lRnhExjGDpOHzgTssKbmJ+bkOPrbXTUWSOY4tkDcdhW6U3AGmBYbGO1Juk8tBkq/xFRl8AeApD6OSSL/fOVID8EikSiG7qK/EJEmiPBOd2lUmPURJ3lKPPsAjxPZhaVQt6CuKvmA5yho1ajMVLdoL3hqYG5hZyjuLqzb4AvpLzjWkzLLcL9JnZhiSl67YHyomAt+VMHjp/rg2qiXoW/ItiWjwkPqK0ZowtSR8Q4/WFEcBx8mlK/Cj45x/LKSjpGLQt/SbdDCtGj2u1UbJMcDx2t/ziMYUhT9N3SStbbqtJumfplarjmXab1y7f5qqU6dOnagf8i84W5AagP7l2QAAAABJRU5ErkJggg==') RETURNING id;");//category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Motor Vehicles, Automotive Parts & Accessories', 'Auto, Tires & Industrial', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAAA1UlEQVRIie2UvQ4BURCF7yxRIqIiosJjewLvoFlBI5EoEI+gFrF8milurp87N0gknGoz+51zZopd5/76agENYAjsea4TkAO9lPAmsIwEhxqnbL5Q0wroRviqsgdLeB2Yq2ENtAyeTPkiBtaAmcIbS7i5QM+cKrgF2pZw9YqlYKTQDuhYwz0/wDmciwccnXOV1OBAFxEp+YPMe341/K6yOPKayimwiEg4A/CR8P13XRBsa9LHL/ALnn/mNt1k+AWzNxQ8zgAGwAQoEn/RqCcH+m9Y8td0BU99R2bmnxZMAAAAAElFTkSuQmCC') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Beauty & Personal Care', 'Cosmetics;Health, Beauty & Personal Care;Hygiene', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAACPUlEQVR4nO2bP2sUQRiHXzQQ0ZDUgiKSKkQFEVSMprFKUBCiXyB+A8FCFIxKUgf/1CpcCDlioZV2iaCVtYX4AQxaREVBk/jIkCHIMXuJzO7M7M77wFbHzu+d52bn7t7bFVEURVH8AU4Dbc/jAXAJ2CV1A7hCebwDDknGAgwfgH7JWIBhSjIX8F4asAn68EvqDp5I3UEF+CF1BxXgh9QdVIAfUkeAfcBRYAx/xuxYeyV1gIvAC+An5WPGfA5ckNQABoHXhGMJOCwpAIwCXwjPZ+Bs7MkPAavE4xtwJNbk9wAfiY/pG/TGEHC9oKAN4AlwxnwalPSJMgI8Bf4UZF4rZ1Y7BNgNrDgKWQMmpCKAyzajk09B+4jAuYJ34laA7NsF2SNVZ28B3HQU8KOMJb8dQF/B94wbVWdvATxyFLAkgQCWHfkPJWABC44CFgPmLzryFyRgAW1HAe1c8iV2AbHzpYRubxWoANEVEAj0EkD3AMrF/MiZBybtMQes57IJ/gbGHRnn7WuNFzDVJeduDgIOdMk5mIOA3m26To0XcLxLzokcBLS75DzLQYDhMTDwz/gDtq9IUwTMA1eBadvKdmHa6y+BV8DX/xw/aQHTHeeeLGhs+pKsgP2O89/kLuBtTgJmOs49ldslgG2imk1wBvhONSQtIAQqQAKugDnSoxVSwD3S405IAcfs3+CpsBH8Rgk2H29JhdmgkzcAPcD9yCvBZM+aWiQWbN7DZ1pXrRIemtrp0bKZw9EmriiKIg3gL31Q7N9UOef0AAAAAElFTkSuQmCC') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Drugs & Medications', '', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAC6ElEQVR4nO3by4sUVxTH8Ts+QAUFYYIzEtC9joriRrJOVq4kW0MIGh0JulCI+FgmvhbR1WShZi36B6gkoKIEdOljkWXMBDOObrJQfHzkMtWh7ame7sxUVVd31Xdf99zfPefcx7m3QqipqampKR8YwS4cwmlcxHkcxVfYgKEwSGAF9uN33fEnzmB96GewGPvwj/nxBhMYDv0GPsUt2fAMn4d+wUwexzDOkrcYD2UHWzHdhaCnuINruIFHeNfFd+P9LP5fnMLmNt+vwV780SESvgh9KP5KFNhlW0txEK/nmBOG+0X8exyfz9qOzzDVpt2JUAawBc/nEP/dAtvfgVdtlsh12SnJx/MHMrIT0yGNH7Jov5Seb7G1BE9S7DzMykYpPd9ic08be+sHXnzTISptn7A7DLr4BnicYvf7MGg53w7cTLH9Uxh0zzdIts2tXAqD7vkGuJvShx9DD7e3R3IzPrsvQ5hM6cPBXp7q7mFVLh1Ij8Q0dvbySFvYICT1w1biFnllkTnfjgdYnWlHPu7TaHKUbuV6Lz1fSCQkuX9VOnvLIj63QcAJ6fyNZb0M+9zTIakOxaU2jW/K5PnMIyFuruYQ/ysWZSF+LAfxCx6EDuJjtXk0q7r9XzmJn/cgdBD/AhuzurG5nbP4/z0IXYjftmDxkVhbVywdJ8YOE95LbA8ZXlROKZ62kVCY55uM9YpZg1Co+Aju6y3/pUNhYd8Aa5WDGAlHCvV8BF8qP/mIj+CwcpN92DeDs6oqPoJflDfst4a8wQVV9HwDHFNV8RF8rTxMFxL2zWCTKnq+QSwiFHAELp/nm8G5yoqPxPv05HlJNcI+DfxcOc83g0+Sp2bVE98gPjbs8mXm4IlvgG8rkfNzkVRkso6EyXbPYUuJmXTIak74LRZeQr+B4WR1mO8S+SwpcS38xqYE+4RzyXP2TrxPfoOJv8MsD4OEmWvpscSrsZByOXnxHaPkZFJeG+l1P2tqampqwmw+AO2Rw/WiIGDFAAAAAElFTkSuQmCC') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Sports & Outdoors', 'Sporting Equipment;Outdoors & Camping;Hiking;Hunting;Fishing;Biking', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAEPElEQVR4nO2a34sVZRjHv0+aGbEJ/boo291ItwQTFOumGyP6edWvTQsCY8OLCrzrOnRRwrv+AV2NfghhGwTSTd0VsSW1IpFFF5ViJbWK7rrqfrqYM3Cc887sO3Pmnfdo53N1ZuZ9n+/zPPP+mHnmSH369OnzP8ZiO+ACuF3SS5LWt059J+kDM/s7nlcNAWwGztDJDDAa27+gAE8AlxzBp1wCHovtZxAAA34sCD7lGNCTU7crgHUewaesrUv3uroM1cBwibb31CXaSwn4t0Tbf4J5EQvgxpzVP8sMsLwu3Z4ZAWY2K2mPR9N3zGwutD9RAJYA7xfc/feAJbH9DArJdvgy8CVwtjUtvgC2XDPbH7AM2AH80bqzl1v7+5bYvgUHWAMcKRjmb8f2MRjAg8BfHiv99ti+1g7wCH7bXDolnovtc20AzwMXPINPOQc8FNv3rgFeAOZLBp9yErgrdgyVAUaBixWDT/kKuCF2LKWpKfiUidjxlAJ4scbgU96MHZcXwDMUV3WqMg9sqtvfWh8tgfslTUm6qaKJI5KWS1qTc31G0m5J+yTNF9g5Z2ZF18MAfNLFHf4cGABWAr92OVqaL54Ct1B93k8A17fZuhc40UQC6qwHrJK0tEK/dyVtNbOL6Qkz+0XS45JO1+RbLnUm4GzJ9pclvW5m282M7EUzOyrpaUln6nAuOCTFjDJzd8zT7kZgKtQUqHsXeFbSx552j0p61Mz+9LQ9JGlI0jKP5tNmdsrHbu0Ar5C8yPgwDdwRxdGQAIPARyWScGtsn4MAbAK+90jCZ7F9DQawFHgDOL1IEh6O4V/pRRBYIelJSWslrWyd/l3StKTDZubctoDbJI1Lek2Sq7S9x8zeCqXfNcAwcIDiys4FYD/Jip1nZz1w3NH3wyb0qwa/DZhbZAi3M0vBPg8cdPQ52JR+2eB3lRDOMt5tAkLolwl+W47hBeAbkpeYidbvhZy2HXfCNwGh9H2DH8Y97A4BqxztVwOTjvazwGDZBITU903AAYexcQq+z5F813MN2X0VEhBM3yf4FXSutoeKxDNOZO/EHDDgm4DQ+j4J2JwxsIBj2BX0H6FzTo62XV8sAUH128mrBzyQOZ4ys599HTCzn5T8ubGddb79m9TPS8CdmeNjvuIFfbI2i2hMPy8B2QpNlbpBtk9H1aeAxvTzEnAyc5xXpi4i2+dEib6N6ecVMX/IHG8EVpvZcR9l4D5JGwpsfu3o1n4utP6iBm52bEOTJbahT7vZhmLrp4YmHFvVriInWuK7Hf32lhLvAX0BQySPkVkmgRFH+xFH5gHOA3dfbfqp0TGHQUgeMqZI3r33A9+S/zLyaiXxHtBPnRjPMezDzq7Ee0A/dWIM93DM4zywtRbxHtBPnRgkWZiKKjNzwF6qzrkI+lWKogOSntKVRcnflHzpOWxmZb8RXlX6ffr06XNN8R8f+FLdSRxelgAAAABJRU5ErkJggg==') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Real Estate, Property & Housing', '', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAC4ElEQVR4nO2ZPWgUURDHN1FEQQ0RIxiRoE0g2IiNgfRaGBRjSLAINn4UVkGwUJtUIY2VgYhgJ3jgV6EgEQIWNqIighFUEFQQsdDgF8b4k4ezOLfs3u3d7t7t5uYHw3HzZt6+98+8j9t4nmEYhmEYhgIosfwoeXHBBMAqgOWHLQHP9oB0NsF5YBToktiNwBjwpkLOe2CX2JGImN8qZrBKOe9TsWE2l9USeAasj8jpAl5H5E2ruJXAp5CYRRWzrYoAPVXGfyMrAQ6omL3ARfepfCMReXsC/V9OSwDgKHAsYE+yEqBb2lcD38X3DVgr/nUhOZ+BVYH+96cogFs6cUhFgC3SvgL4qPxXgRmx4ICuqH4H5HMN8LWIAhxSMTuB+zEePCLxG9zaVPnXiyjAS7frB2J3A7cj4n/6myZwEPjiNkH5PpaGACFjP5elAMhxNxiS4yb0i3LuqPYL4utXFbFYRAF8HgNDgbwpyjmu2l6I76zy3UthCdwFZpW9avRNcEblbVX+JWCzatsutkn5ThZpD5hV7e6s1ehJ+cvgQYznOMH+FEWAd0C7GuCC+D+oja1DxZ9W/Q2578r6VNvDogjgGFUx3e5m6N8NxHeY//Qq/1vKmVJtZ0IEaAc6A9YTIUBniN0kIwEWgtdalbNDqsHxXPl7Q/p5pNr7ggJE9N9Rw2+BUtab4BxwSu7+J4Brcub7PAUmxW6F5C/JieHH/BDfZAU7r/Knq8TOZy1AETEBPKuAmGBLgJbfA8alCrKy4L0A8WX5zHEvL5D0nC46mABYBWBLoMB7ANCmXnFVJGkFxHkGcMn/qZ6ryTsaJEBjRKDGyTdYgGxFoI7JN0GAbESgzsk3SYB0ReDf5N2/vOoios9+YDhg/SkKgIy5rWl/eZ9EA0gmQLJKIIXJ50CA+kQgpcnnRIDaRQAmUnpwXgRwTDTrhchwQksLeyfoNakC8oIJ4FkFxIRWXwKGYRiGYXitwF+FAy8M28uvbgAAAABJRU5ErkJggg==') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Luggage & Travel', '', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAC9klEQVR4nO2bPWjVUBiG38+K2C7iLzhZVyc7O/iDojhY3HSxautYFQQXF0HB2cEiKCLqIEoFCwoiaKU4V0REKFpxrFY61EFrfRyuQr3kJLnJPTkxNw90yTnN95435+R+J/ki1dTU1HQw5uOkwFFJ+5sOz0gaNjN8xCwVwAGiORFaWyEA3cB8hAFzwMbQ+goBGHXMgjuhtRUCcMRhAEDz/aF6AGuABYcBU0B3aI3eAZ7FzIKLofV5BzgVY8B3YEtojV4BNgG/YkyYALzkIqUBmIwxAGAotEavAOcTDJgFNoTW6Q1ga4IBALdD6/QK8CGFCXtCaFtWUJyxFH1GqGpuAOxMMQMALoTW6gWgC/icwoDCc4PIJQAMAveW/A3mCWJmi5Iep+i6QtJVQucGwLGmK7MAbMt5zoMplwF5Dc8NsDlC1CdgXY5z9gDfUhoQPjcAPkYIe0SO6Qk8bGEW3GrneLKIvekQdibHOY+3YADA7naOKYrlMW3jkgYijl8C5iV9zRBvZYv9R4BzGeL8kDRtZq+TOjqnM9AraTpD8DLxTtJJM3vq6hC7noFpSb3tVlUwi5IOm9n9qMakVHi8/XoKp0vSNRy/YEkGvGi/niCsknQoqqETZsBf+qIOFrUbLAORr+SSDNjhQUgoJqMOJhmw3YOQEMxJuhvV0AkzYFHSkJnNRjU6DfiTCP3vOcBbSXvNbNTVIS4Vdl39BUnDypYKr5d0pYX+U5KypsLvzexNhv9t4GkzNFi2zVCcWB/b4bEWBh9uO0wHPRBx3QSb1/9PNTYUX3LE2iepJ2Xfs2Y2kyNWalw3wWWSlu6enpjZy5yx+lP2m5B0I2esckGJH4sXArAr5dqv7IuRyykGX92yGUr8ctQ7QF+KwVf39Th1gQSvEgyobokMjSKpOKpdJAWcjhl8NX/zlwI8jzGg2oWSwFo6uVQWGIi5+h1RLP3AMfjql8vT6R9MAP2Oq1+6T2biHormYbX+fZ4gNT6auu4pXk1NTU1NFn4DHMdp490i7dkAAAAASUVORK5CYII=') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Business, Industrial & Scientific', '', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAADDUlEQVR4nO2ZvWsUQRyG30lSaCJiVLSKYAoxooJIIIWiWImFYJcEYmnhPyD4B6iNpcFCUAjEkAQsRC20ERTxA4JFijSCImgR/IhJUHPJY3GJKN7uzsztZO5knubgbnbe9/fu7MzsnJRIJBKJRCLRwABbgBd4ENt73dRTvE0AbY5mdknqltQpaVbSlDFm3q80K71OSQ8lHQ6lYWOiFTgLvK4R8BJwBzgUQLcTeOV7521HQJGJrcAjC50KcKGk2ksr3iaAzEcA2CDpnqQ+C8+tkq4AFWPMVftS/9JrkXRK0vHVz56MppOSxn00XA1d8gj8J7DfQ6sLeG7R/xjgNG95QXXoL3gEAHDbUWsTMN0wxa+aGvIsPhTjBCq+JeP7eMvOv0xIGjTGVEJ0nhXA9hBiHjxVwOKl7AAWQgk60iepP6RAVgAzIUUdaJV0CxgIJWBqfQn0SJrO+r2AKUmXHdp3SLomqT2nzbKkIWOM0wpTF8B9zxn7tIfWGYqX3QowGKLWLFPdwFfH4icBn1EjoAe4CbwFlhslhKPAF8viPwB5w9hF9xgw7xh+Tcowsxu4C6wUaK0A+0qof023lBDK8iNgDzBcoHe9NEGVE0KZfgS0A7M5eovAtpI1jwBzoQLI2gfUxBizKOlGTpONks659Gmh+UTV1+NvZfb7u3/XC4AuSW+UfZbwXlK3MWapHmM1dA9I2ut6nTFmokwfa2bGCkZesJ1bQwD0FgTwMrbH4ADPCkKwOUprXoD+ggDWb98eA6ANeJcTwBLVCbOhcVoG/2T1kGI4p0mbpPO+/TcFVM/v83Zqn4CO2D7z8B4BkmSM+SxpJKdJp6ShejQaHqrvCFmvrwAzVP/0+H8BHhSsCCdje6wb4CAwCnwsKHa9mQceAwN4HsbYFD8I/Ihaph0jlP24Ub3zzVD8Ghdd6iscMsCopGZ6uZmTtNMY892msc1wOVGfn3Vns6Re28Y2Aezw9xINa882AYSZWcNiPRH+3xsUC1IAsQ3EJgUQ20BsUgCxDcQmBRDbQCKRSCQSiUQsfgGI7rZpsWTP5QAAAABJRU5ErkJggg==') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Illegal', 'Banned and/or prohibited items', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QA/wD/AP+gvaeTAAAFDUlEQVR4nO2bzW9WRRTGn2ljEaVFSghl40fStC5cYcNOSXVjQmo0fqAsWGI1oWyQmFQihkDUFQQ2xqVGoqa6smGPfwENkmoMpUHBapR+CG2I/bmYt0rrmfs5975NeJ/lvTPnOee5c+ecOzNXaqGFFlq4h+HqIgK2S3pCUr+kRyQ9JGlT4/aCpD8lXZX0g6QJ59xMXb5VAqANeAY4C3xPflwCzgCDQFuz48kMYCvwHjBdIOgQrjZsdjc7viCAzcBHwHzEwNdiHvgQ6Gp2vKsA7AOuVxj4WvwCvB7D91KTYONJfCLp1RzdFiRNSbohaV5Sm6QHJfVI6pV0fw5b5yS94Zybz9EnDoDHgR8zPK1FYBw4DOwkYULDT5z9wAFgrNE3DZNAX52xC9gF/Jbi2AzwPj79FeXZAozgJ8E0roGYMSY5tYvkie4WcATIM5TTODuAg8DNBN65ykXAD/ukJ3+BCocj0IN/nZJGQjX8QBfJ7/wyMFQJ+Wo/HDDa4LMwCXRWQfxFQvArWAT2RCe3/dkP3An48Xlssn0Zgm+WCKGRsDcWyWbCRU6IvE4RRgM+/EyMVwFf3lq4AAwRztW1iICvHUIT48myxrdip7xbNGZbYM86EKEHO0XOUeYDCjgWCOztNe3WgwgjAf6jRQ22YX/SzgAbjfbPAbcDTiwBz5eOMtnf+4Apg3uKIusJwLOBYI4l9GnqSAAOBbh3FzF21jB0m5TavpkiAN0B7tNFjFnLWOMZ+zZThG8Mzom8RrZj5/jDOWw0RQRg2OBbBrblMRJ6/3fmdKZ2EfAfbBYG8xh5yzAwT4HZtG4RgHbsbDRstQ8F9Khxbco5t5zXIefct5JekrRk3N4gaSymCM65vyX9ZNyyYgoKYK26Xi/hVK0iSLI2VTZbDUMCbDKu/VXYHf0rwguSFo3bGyR9TbxiyVoktWIKCmCh9Daac+68pBdli9Ah6atIIpC1YUiABeNalFWWhggvy34dOiR9GeF1sJ62FVNQgDnjWvY8moIa5oQdxrVZq2FIgCnjWm+RNBhCVSIA7QpksTxGQoVQf16HMnBFrROAgYCtXIVQqBQ+kDvCbHzRRMDvSaxFvlK4YeiSYWgsd3TZ+aKIAJw3+l8s4tCZgCNbchvLzllKBPzSmNX/VBFnBgOOjBSOMBtvYRGA44F+TxdxxAFXDGPTQEepKNO5cy+vAQ9gb9tNAcWKOPyxFAsHS0eZzp1rJADvBNoWWxRtGO3GLy2vxU2gp3SU6fyZRMCfKbBGzCxl5yzgg4AD49RweiuDCEPAd4H7J2I40IU/k2NhNEKMWXxIEiG0PXeNWLvEwGsJ5PujkKT7kCSChVdiO3AuQHRnHYrwaRXknfjDB6GRMErRdJPPjyHCwx7gMmAufsQg78NvjYUwToXZAT/bhyY8gF+B3qr4V5wYwE6NK7iJ36iMViwBG/F5PlQcgU95T8biTHNoIGUkgK8YD1Fiexpf2x8n/UjejdqCv8u5PsJzwt1YxG9XDeM3LdoTbLY3xD2C/6rLMuFdpsSwL3tUtlPSx5LynNtdkl+3Xzkqi/x64w5Jj0n639Z7Aj6T9KZzzlzvqw3AXvyZnLpwjdh5vizwafIkyRNkWcwCJ6jiHGAs4D+gjmKf1iiKK8C7VLgYEx349YTdwGlgguTiZS2WgYvAKeApKiyw6vxpapv++2nqYUndWv3T1B+SpiVNyv809XtdvrXQQgst3LP4B1dCXq0t0BR7AAAAAElFTkSuQmCC') RETURNING id;"); - category_id = database->get_integer("INSERT INTO categories (name, description, thumbnail) VALUES ('Miscellaneous', 'Others;Non-classified', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAACbUlEQVR4nO2aT4oTQRSHS5mlbkTRCyg4oxdQZ+sJTFzPKUTcCK7nAEJWji4mzBHcZDMqguNC8ABKZlZDsjIb88ljSgjdVd1J6k+69H3QkG5eNfX7db1X1Z0yRlEURVGUTQBcMqUA3APeAWd0l1Pbx53Y4p8CM8pB+tqLJf5+YeL/MosyErgYUqVyEMOAM8rlNIYB80yd/SB5G3DsO+45j2FALoaB/RQTaqgBoZAPHQEm7EFpCqA1oI7WgFDIh9YAE/agtAagNaCO1oBQyIfWABP2oLQGUHgN+CFpEHAcl25AEtSAUCgcNSAU3Bw3FKOvwAR43xAjBa+tCI5aHu5ok0Ww54l9tfAV+RzY9cRJh73rAOAW8L1B/Ovq/4q51wE9R9wdxyf0L6sasI74rhjw2BE3WcWAdcV3xYBrdtgvcriCAaN1xdt79jdqgCA5L8PeFsFD4LpZ3gACxHtHjkllAPACGNvjeUP7G8ARMAVOrEnDHOJTGnDkuNb3tK/GntspMrn4lAZMHdcGnvau2EkO8SkNOHFcc6aBI3buaR9dfEoD9oBPC+cfgSue9rsLs4OIf9lSA6KJT10Et4CHwAP5bWOv2uI4kH1FlSlS1gm37fkwh/ikBph6nBjyecm08K0DQsTnnQZNPe6RI268ggHeb4LATeBbg/jBxhdCXKRDlZ+hBiwp/nIXlsJblcIoPAsxYJV3g5QGzB333fdsVNqzU9zUivRtaJINUW2bpPpL5Hy/ZZPU7/99m9w4hgFvKZc3MQzYKXSr7C9gO9gAwebarDDxT0xMgG2bDvL621WkbwfA3ajiFUVRFEUx/yJ/AKs6hY9h/vEkAAAAAElFTkSuQmCC') RETURNING id;"); - //category_id = database->get_integer("INSERT INTO categories (name, description) VALUES ('Collectables & Art', '') RETURNING id;"); - //category_id = database->get_integer("INSERT INTO categories (name, description) VALUES ('', '') RETURNING id;"); - // NOTE: Categories also act as tags to be used for filtering specific products - } - //------------------------- - if(!database->table_exists("mappings")) { - database->execute("CREATE VIRTUAL TABLE mappings USING fts5(search_term, key, content, tokenize='porter unicode61');"); - } //------------------------- database->execute("COMMIT;"); } @@ -290,7 +209,15 @@ std::string neroshop::Backend::getDatabaseHash() { QVariantList neroshop::Backend::getCategoryList(bool sort_alphabetically) const { QVariantList category_list; - for (const auto& category : predefined_categories) { + std::vector categories = predefined_categories; // Make a copy + + if (sort_alphabetically) { + std::sort(categories.begin(), categories.end(), [](const Category& a, const Category& b) { + return a.name < b.name; + }); + } + + for (const auto& category : categories) { QVariantMap category_object; category_object.insert("id", category.id); category_object.insert("name", QString::fromStdString(category.name)); @@ -298,21 +225,22 @@ QVariantList neroshop::Backend::getCategoryList(bool sort_alphabetically) const category_object.insert("thumbnail", QString::fromStdString(category.thumbnail)); category_list.append(category_object); } - - if(sort_alphabetically == true) { - std::sort(category_list.begin(), category_list.end(), [](const QVariant& a, const QVariant& b) { - return a.toMap()["name"].toString().compare(b.toMap()["name"].toString(), Qt::CaseInsensitive) < 0; - }); - } return category_list; } //---------------------------------------------------------------- -QVariantList neroshop::Backend::getSubCategoryList(int category_id) const { +QVariantList neroshop::Backend::getSubCategoryList(int category_id, bool sort_alphabetically) const { QVariantList subcategory_list; std::vector subcategories = get_subcategories_by_category_id(category_id); + + if (sort_alphabetically) { + std::sort(subcategories.begin(), subcategories.end(), [](const Subcategory& a, const Subcategory& b) { + return a.name < b.name; + }); + } + for (const Subcategory& subcategory : subcategories) { QVariantMap subcategory_obj; subcategory_obj.insert("id", subcategory.id); @@ -373,17 +301,17 @@ bool neroshop::Backend::createFolders() { neroshop::print("\033[1;97;49mcreated path \"" + cache_folder + "\""); } //-------------------------------- - std::string products_folder = cache_folder + "/" + NEROSHOP_CATALOG_FOLDER_NAME; + std::string listings_folder = cache_folder + "/" + NEROSHOP_CATALOG_FOLDER_NAME; // folder with the name should contain all product images for particular listing // datastore/listings/ - if (!neroshop_filesystem::is_directory(products_folder)) { - neroshop::print("Creating directory \"" + products_folder + "\" (^_^) ...", 2); - if (!neroshop_filesystem::make_directory(products_folder)) { - neroshop::print("Failed to create folder \"" + products_folder + "\" (ᵕ人ᵕ)!", 1); + if (!neroshop_filesystem::is_directory(listings_folder)) { + neroshop::print("Creating directory \"" + listings_folder + "\" (^_^) ...", 2); + if (!neroshop_filesystem::make_directory(listings_folder)) { + neroshop::print("Failed to create folder \"" + listings_folder + "\" (ᵕ人ᵕ)!", 1); return false; } - neroshop::print("\033[1;97;49mcreated path \"" + products_folder + "\""); + neroshop::print("\033[1;97;49mcreated path \"" + listings_folder + "\""); } //-------------------------------- // TODO: uncomment this @@ -402,8 +330,68 @@ bool neroshop::Backend::createFolders() { return true; } //---------------------------------------------------------------- -#include -#include +//---------------------------------------------------------------- +bool neroshop::Backend::saveProductThumbnail(const QString& fileName, const QString& listingKey) { + std::string config_path = NEROSHOP_DEFAULT_CONFIGURATION_PATH; + std::string cache_folder = config_path + "/" + NEROSHOP_CACHE_FOLDER_NAME; + std::string listings_folder = cache_folder + "/" + NEROSHOP_CATALOG_FOLDER_NAME; + //---------------------------------------- + // datastore/listings/ + std::string key_folder = listings_folder + "/" + listingKey.toStdString(); + if (!neroshop_filesystem::is_directory(key_folder)) { + neroshop::print("Creating directory \"" + key_folder + "\" (^_^) ...", 2); + if (!neroshop_filesystem::make_directory(key_folder)) { + neroshop::print("Failed to create folder \"" + key_folder + "\" (ᵕ人ᵕ)!", 1); + return false; + } + neroshop::print("\033[1;97;49mcreated path \"" + key_folder + "\""); + } + //---------------------------------------- + // Generate the final destination path + std::string thumbnail_image = "thumbnail.jpg"; + std::string destinationPath = key_folder + "/" + thumbnail_image; + // Check if image already exists in cache so that we do not export the same image more than once + if(!neroshop_filesystem::is_file(destinationPath)) { + // Hopefully the image does not exceed 32 kB in file size :S + QImage sourceImage; + sourceImage.load(fileName); + QSize imageSize = sourceImage.size(); + int maxWidth = 192; // Set the maximum width for the resized image + int maxHeight = 192; // Set the maximum height for the resized image + + // Convert the transparent background to white if necessary + if (sourceImage.hasAlphaChannel()) { + QImage convertedImage = QImage(sourceImage.size(), QImage::Format_RGB32); + convertedImage.fill(Qt::white); + QPainter painter(&convertedImage); + painter.drawImage(0, 0, sourceImage); + painter.end(); + sourceImage = convertedImage; + } + + // Check if the image size is smaller than the maximum size + if (imageSize.width() <= maxWidth && imageSize.height() <= maxHeight) { + // Keep the original image since it's already within the size limits + } else { + // Calculate the new size while maintaining the aspect ratio + QSize newSize = imageSize.scaled(maxWidth, maxHeight, Qt::KeepAspectRatio); + + // Resize the image if it exceeds the maximum dimensions + if (imageSize != newSize) { + sourceImage = sourceImage.scaled(newSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + } + } + + // Convert the QImage to QPixmap for further processing or saving + QPixmap resizedPixmap = QPixmap::fromImage(sourceImage); + + // Save the resized image + resizedPixmap.save(QString::fromStdString(destinationPath), "JPEG"); + } + + neroshop::print("exported \"" + thumbnail_image + "\" to \"" + cache_folder + "\"", 3); + return true; +} //---------------------------------------------------------------- bool neroshop::Backend::saveProductImage(const QString& fileName, const QString& listingKey) { std::string config_path = NEROSHOP_DEFAULT_CONFIGURATION_PATH; @@ -414,18 +402,18 @@ bool neroshop::Backend::saveProductImage(const QString& fileName, const QString& std::string image_name = image_file.substr(image_file.find_last_of("\\/") + 1);// get filename from path (complete base name) //---------------------------------------- // datastore/listings/ - std::string products_folder = listings_folder + "/" + listingKey.toStdString(); - if (!neroshop_filesystem::is_directory(products_folder)) { - neroshop::print("Creating directory \"" + products_folder + "\" (^_^) ...", 2); - if (!neroshop_filesystem::make_directory(products_folder)) { - neroshop::print("Failed to create folder \"" + products_folder + "\" (ᵕ人ᵕ)!", 1); + std::string key_folder = listings_folder + "/" + listingKey.toStdString(); + if (!neroshop_filesystem::is_directory(key_folder)) { + neroshop::print("Creating directory \"" + key_folder + "\" (^_^) ...", 2); + if (!neroshop_filesystem::make_directory(key_folder)) { + neroshop::print("Failed to create folder \"" + key_folder + "\" (ᵕ人ᵕ)!", 1); return false; } - neroshop::print("\033[1;97;49mcreated path \"" + products_folder + "\""); + neroshop::print("\033[1;97;49mcreated path \"" + key_folder + "\""); } //---------------------------------------- // Generate the final destination path - std::string destinationPath = products_folder + "/" + image_name; + std::string destinationPath = key_folder + "/" + image_name; // Check if image already exists in cache so that we do not export the same image more than once if(!neroshop_filesystem::is_file(destinationPath)) { // Image Loader crashes when image resolution is too large (ex. 4096 pixels wide) so we need to scale it!! @@ -470,7 +458,6 @@ QVariantMap neroshop::Backend::uploadProductImage(const QString& fileName, int i product_image_file.seekg(0, std::ios::end); size_t size = static_cast(product_image_file.tellg()); // in bytes // Limit product image size to 12582912 bytes (12 megabyte) - // Todo: Database cannot scale to billions of users if I am storing blobs so I'll have to switch to text later const int max_bytes = 12582912; double kilobytes = max_bytes / 1024.0; double megabytes = kilobytes / 1024.0; @@ -1017,7 +1004,6 @@ QVariantList neroshop::Backend::getListings(ListingSorting sorting) { listing.insert("product_description", QString::fromStdString(product_obj["description"].get())); listing.insert("product_category_id", get_category_id_by_name(product_obj["category"].get())); //listing.insert("", QString::fromStdString(product_obj[""].get())); - //listing.insert("", QString::fromStdString(product_obj[""].get())); if (product_obj.contains("images") && product_obj["images"].is_array()) { const auto& images_array = product_obj["images"]; for (const auto& image : images_array) { @@ -1033,6 +1019,9 @@ QVariantList neroshop::Backend::getListings(ListingSorting sorting) { } listing.insert("product_images", product_images); } + if (product_obj.contains("thumbnail") && product_obj["thumbnail"].is_string()) { + listing.insert("product_thumbnail", QString::fromStdString(product_obj["thumbnail"].get())); + } } catalog.append(listing); } diff --git a/src/gui/backend.hpp b/src/gui/backend.hpp index 62a9a93..6754ad4 100644 --- a/src/gui/backend.hpp +++ b/src/gui/backend.hpp @@ -37,6 +37,9 @@ public: Q_INVOKABLE QString urlToLocalFile(const QUrl& url) const; Q_INVOKABLE void copyTextToClipboard(const QString& text); + + QString imageToBase64(const QImage& image); // un-tested + QImage base64ToImage(const QString& base64Data); // un-tested Q_INVOKABLE QStringList getCurrencyList() const; Q_INVOKABLE int getCurrencyDecimals(const QString& currency) const; @@ -48,7 +51,7 @@ public: // TODO: Use Q_ENUM for sorting in order by a specific column (e.e Sort.Name, Sort.Id) Q_INVOKABLE QVariantList getCategoryList(bool sort_alphabetically = false) const; - Q_INVOKABLE QVariantList getSubCategoryList(int category_id) const; + Q_INVOKABLE QVariantList getSubCategoryList(int category_id, bool sort_alphabetically = false) const; Q_INVOKABLE int getCategoryIdByName(const QString& category_name) const; Q_INVOKABLE int getSubCategoryIdByName(const QString& subcategory_name) const; Q_INVOKABLE int getCategoryProductCount(int category_id) const; // returns number of products that fall under a specific category @@ -75,9 +78,9 @@ public: // Products should be registered so that sellers can list pre-existing products without the need to duplicate a product which is unnecessary and can make the database bloated Q_INVOKABLE bool createFolders(); - Q_INVOKABLE QVariantMap uploadProductImage(const QString& filename, int image_id); + Q_INVOKABLE QVariantMap uploadProductImage(const QString& filename, int image_id); // constructs image object rather than upload it Q_INVOKABLE bool saveProductImage(const QString& fileName, const QString& listingKey); - + Q_INVOKABLE bool saveProductThumbnail(const QString& fileName, const QString& listingKey); Q_INVOKABLE int getProductStarCount(const QString& product_id); // getProductRatingsCount Q_INVOKABLE int getProductStarCount(const QString& product_id, int star_number); diff --git a/src/gui/user_controller.cpp b/src/gui/user_controller.cpp index 51b874c..44df5ea 100644 --- a/src/gui/user_controller.cpp +++ b/src/gui/user_controller.cpp @@ -82,6 +82,7 @@ int quantity, double price, const QString& currency, const QString& condition, c if(imageMap.contains("name")) image.name = imageMap.value("name").toString().toStdString(); if(imageMap.contains("size")) image.size = imageMap.value("size").toInt(); if(imageMap.contains("id")) image.id = imageMap.value("id").toInt(); + if(imageMap.contains("source")) image.source = imageMap.value("source").toString().toStdString(); //if(imageMap.contains("")) imagesVector.push_back(image); @@ -169,6 +170,22 @@ void neroshop::UserController::rateSeller(const QString& seller_id, int score, c } //---------------------------------------------------------------- //---------------------------------------------------------------- +void neroshop::UserController::addToFavorites(const QString& listing_key) { + if (!_user) throw std::runtime_error("neroshop::User is not initialized"); + _user->add_to_favorites(listing_key.toStdString()); +} +//---------------------------------------------------------------- +void neroshop::UserController::removeFromFavorites(const QString& listing_key) { + if (!_user) throw std::runtime_error("neroshop::User is not initialized"); + _user->remove_from_favorites(listing_key.toStdString()); +} +//---------------------------------------------------------------- +bool neroshop::UserController::hasFavorited(const QString& listing_key) { + if (!_user) throw std::runtime_error("neroshop::User is not initialized"); + return _user->has_favorited(listing_key.toStdString()); +} +//---------------------------------------------------------------- +//---------------------------------------------------------------- void neroshop::UserController::uploadAvatar(const QString& filename) { if (!_user) throw std::runtime_error("neroshop::User is not initialized"); diff --git a/src/gui/user_controller.hpp b/src/gui/user_controller.hpp index 64bdc30..b59b3a5 100644 --- a/src/gui/user_controller.hpp +++ b/src/gui/user_controller.hpp @@ -69,8 +69,10 @@ public: Q_INVOKABLE void createOrder(const QString& shipping_address); Q_INVOKABLE void rateItem(const QString& product_id, int stars, const QString& comments);//, const QString& signature); Q_INVOKABLE void rateSeller(const QString& seller_id, int score, const QString& comments);//, const QString& signature); - //Q_INVOKABLE void addToFavorites(); - //Q_INVOKABLE void removeFromFavorites(); + + Q_INVOKABLE void addToFavorites(const QString& listing_key); + Q_INVOKABLE void removeFromFavorites(const QString& listing_key); + Q_INVOKABLE bool hasFavorited(const QString& listing_key); //Q_INVOKABLE void setID(const QString& id); //Q_INVOKABLE void setWallet(neroshop::WalletController * wallet); // get the actual wallet from the controller then set it as the wallet diff --git a/tests/request/request b/tests/request/request index 9b1cf67c92595cbc7c7268c8f0ede41a2c268222..9153f9519c6ddb8cc5b62057fb527d58b1a92cbe 100644 GIT binary patch delta 763 zcmYk4T}TvB6vyuwcbhi+tku<2b`5K?2iFCmD5pn642@*y zNtiq?l{w2LS|~^*tp~GVjy$QXczxkL@4D3G_R7If=W(^P?cT4>BVs7eQ%i^WZEZgV z#kAH!%1@sN)LnO1zu(MQ(Q_BwP*Ud7wRuXWt(5t}qO>(!@Peo7^}>s}3TwFZtk@Eq zB8rOnhOb3c=Q?_Ny3U{O-M4L1;LqxJcKwVAcXKaYnffH<8lKtrMao)YYyfNmy|Yrz zA-@iOL>!w#9oRmPIFGSWa1Bg@apYM>%0BQGI0gI^2|iNT zUbeg>U)l}e$ zI3i{i77r?V!3O0J>arExNJn|X(C8$;WB4IC4nM|c9KUL4&H0!|y*;15-Fe%|ZpVGh zh0ooJ`9!hLohwF8{TTWz-eGDq%af*`ruiuR0-rRs8Wm$J`@b*hv^ly{&|T*x5kD>R z5c~xmgMT0rkqI~d;R}d{))6>!rkQPq}Vi T!&o^VN7Nn3M%`jH@lg2J<{4n|wLLY={!9E2`h+ZfJgQ7$&p;;>tf-sDy|DCY9aL(_Z^PKa4&OO}N3dL4v z%1d^)jin#A(Mle2gj+Vl40%*qEu5X&>&>5eHX3P|*x6K7(0G1*=72F~vAZe4?;3H5ZiM?p?Fxn{dPGU{gGR(~1Ql(rNPuPa$j&Ci9!>cJlE_)kQ)6 zT&;BeDPgRnWUDRv24*)!Op9~7rj)HOVE{x-&&|IosX1Gu!>HS=2qRs^1DZl!KBT!I zc@O?JkEi{6O=(VHFV)b@bX#_l*%(@;RiyrYP z{0ly*D`j7>Kj;5_ZRxhO?i_UI`5J0pa)-}F?YtI#*a-NZSdE$^F)NMm*}w@38?_y8 qtQ0fo*r8(T;mv&>`@g?;sBgc$UNx^^te(dajrlgCF=M^&f%F$GHu~ZK diff --git a/tests/request/request.cpp b/tests/request/request.cpp index b1921a5..fb0f03b 100644 --- a/tests/request/request.cpp +++ b/tests/request/request.cpp @@ -23,7 +23,7 @@ int main() { "jsonrpc": "2.0", "method": "query", "params": { - "sql": "SELECT * FROM categories WHERE name = 'Food & Beverages';" + "sql": "SELECT * FROM mappings;" } })";//"{\"id\": \"5135958352\", \"jsonrpc\": \"2.0\", \"method\": \"query\", \"params\": {\"sql\": \"SELECT * FROM users WHERE name = 'layter'\"}}"; diff --git a/tests/request/request.sh b/tests/request/request.sh index bc29b16..c4252c6 100644 --- a/tests/request/request.sh +++ b/tests/request/request.sh @@ -1,6 +1,6 @@ #!/bin/bash curl -X POST \ -H 'Content-Type: application/json' \ - -d '{"id": "5135958352", "jsonrpc": "2.0", "method": "query", "params": {"sql": "SELECT * FROM categories WHERE name = '\''Food & Beverages'\''"}}' \ + -d '{"id": "5135958352", "jsonrpc": "2.0", "method": "query", "params": {"sql": "SELECT * FROM mappings;"}}' \ http://127.0.0.1:50882 # -d @./request.json \