add favorites (wishlist) feature

pull/165/head
larteyoh 10 months ago
parent 7df4503d48
commit 45a3ade1cb

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

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

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

@ -44,26 +44,40 @@ const std::vector<Category> 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<Subcategory> 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<unsigned int>(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<unsigned int>(predefined_categories.size() + 0), predefined_categories[5].name, predefined_categories[5].description, predefined_categories[5].thumbnail, 7 },
{ static_cast<unsigned int>(predefined_categories.size() + 1), predefined_categories[5].name, predefined_categories[5].description, predefined_categories[5].thumbnail, 8 },
{ static_cast<unsigned int>(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<unsigned int>(predefined_categories.size() + 3), predefined_categories[25].name, predefined_categories[25].description, predefined_categories[25].thumbnail, 0 },
{ static_cast<unsigned int>(predefined_categories.size() + 4), predefined_categories[25].name, predefined_categories[25].description, predefined_categories[25].thumbnail, 5 },
{ static_cast<unsigned int>(predefined_categories.size() + 5), predefined_categories[25].name, predefined_categories[25].description, predefined_categories[25].thumbnail, 6 },
{ static_cast<unsigned int>(predefined_categories.size() + 6), predefined_categories[25].name, predefined_categories[25].description, predefined_categories[25].thumbnail, 7 },
{ static_cast<unsigned int>(predefined_categories.size() + 7), predefined_categories[25].name, predefined_categories[25].description, predefined_categories[25].thumbnail, 8 },
{ static_cast<unsigned int>(predefined_categories.size() + 8), predefined_categories[25].name, predefined_categories[25].description, predefined_categories[25].thumbnail, 19 },
{ static_cast<unsigned int>(predefined_categories.size() + 9), predefined_categories[25].name, predefined_categories[25].description, predefined_categories[25].thumbnail, 23 },
{ static_cast<unsigned int>(predefined_categories.size() + 10), predefined_categories[25].name, predefined_categories[25].description, predefined_categories[25].thumbnail, 24 },
//{ 0, , <category_id_goes_here> },
// All categories
{ static_cast<unsigned int>(predefined_categories.size() + 11), predefined_categories[0].name, predefined_categories[0].description, predefined_categories[0].thumbnail, 25 },
{ static_cast<unsigned int>(predefined_categories.size() + 12), predefined_categories[5].name, predefined_categories[5].description, predefined_categories[5].thumbnail, 25 },
{ static_cast<unsigned int>(predefined_categories.size() + 13), predefined_categories[6].name, predefined_categories[6].description, predefined_categories[6].thumbnail, 25 },
{ static_cast<unsigned int>(predefined_categories.size() + 14), predefined_categories[7].name, predefined_categories[7].description, predefined_categories[7].thumbnail, 25 },
{ static_cast<unsigned int>(predefined_categories.size() + 15), predefined_categories[8].name, predefined_categories[8].description, predefined_categories[8].thumbnail, 25 },
{ static_cast<unsigned int>(predefined_categories.size() + 16), predefined_categories[19].name, predefined_categories[19].description, predefined_categories[19].thumbnail, 25 },
{ static_cast<unsigned int>(predefined_categories.size() + 17), predefined_categories[23].name, predefined_categories[23].description, predefined_categories[23].thumbnail, 25 },
{ static_cast<unsigned int>(predefined_categories.size() + 18), predefined_categories[24].name, predefined_categories[24].description, predefined_categories[24].thumbnail, 25 },
{ static_cast<unsigned int>(predefined_categories.size() + 19), predefined_categories[7].name, predefined_categories[7].description, predefined_categories[7].thumbnail, 5 },
{ static_cast<unsigned int>(predefined_categories.size() + 20), predefined_categories[8].name, predefined_categories[8].description, predefined_categories[8].thumbnail, 5 },
{ static_cast<unsigned int>(predefined_categories.size() + 21), predefined_categories[9].name, predefined_categories[9].description, predefined_categories[9].thumbnail, 5 },
};
//-----------------------------------------------------------------------------

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

@ -137,7 +137,7 @@ std::pair<std::string, std::string/*std::vector<uint8_t>*/> 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";
}

@ -668,10 +668,10 @@ neroshop::User * neroshop::Seller::on_login(const neroshop::Wallet& wallet) { //
dynamic_cast<Seller *>(user)->set_account_type(UserAccountType::Seller);
//-------------------------------
/*// load orders
dynamic_cast<Seller *>(user)->load_orders();
dynamic_cast<Seller *>(user)->load_orders();*/
// load wishlists
dynamic_cast<Seller *>(user)->load_favorites();
// load customer_orders
/*// load customer_orders
static_cast<Seller *>(user)->load_customer_orders();*/
// Load cart (into memory)
user->get_cart()->load(user->get_id());

@ -3,6 +3,7 @@
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <fstream>
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<char> 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<int>(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<char> 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<int>(encoded.length()));
BIO_push(b64, mem);
// Determine the size of the decoded data
size_t max_decoded_length = (encoded.length() * 3) / 4;
std::vector<char> decoded_data(max_decoded_length);
// Decode the data
int decoded_length = BIO_read(b64, decoded_data.data(), static_cast<int>(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!";

@ -2,10 +2,14 @@
#include <iostream>
#include <string>
#include <vector>
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<char> base64_image_decode(const std::string& encoded);
}

@ -11,7 +11,7 @@
#include <fstream>
////////////////////
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<Cart>(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<neroshop::Product>(product_id));//(std::unique_ptr<neroshop::Product>(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<const char *> 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<neroshop::Product>(product_id));//(std::unique_ptr<neroshop::Product>(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<const char *>(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::Order *> 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::Product *> neroshop::User::get_favorites_list() const {
std::vector<neroshop::Product *> 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<std::string> 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)
}
////////////////////
////////////////////

@ -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<neroshop::Order *> 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<neroshop::Product *> get_favorites_list() const;
std::vector<std::string> 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> cart;
std::vector<std::shared_ptr<neroshop::Order>> order_list;
std::vector<std::shared_ptr<neroshop::Product>> 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<std::string> favorites;
std::string get_private_key() const;
};
}

@ -14,6 +14,13 @@
#include <QProcess> // Note: QProcess is not supported on VxWorks, iOS, tvOS, or watchOS.
#include <QUuid>
#include <QDateTime>
#include <QImage>
#include <QPixmap>
#include <QByteArray>
#include <QBuffer>
#include <QPainter>
#include <QImageReader>
#include <QImageWriter>
#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 <future>
#include <thread>
@ -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<Category> 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<Subcategory> 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 <listing_id> 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 <QImage>
#include <QPixmap>
//----------------------------------------------------------------
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/<listing_key>
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/<listing_key>
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<int>(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<std::string>()));
listing.insert("product_category_id", get_category_id_by_name(product_obj["category"].get<std::string>()));
//listing.insert("", QString::fromStdString(product_obj[""].get<std::string>()));
//listing.insert("", QString::fromStdString(product_obj[""].get<std::string>()));
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<std::string>()));
}
}
catalog.append(listing);
}

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

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

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

Binary file not shown.

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

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

Loading…
Cancel
Save