792 lines
43 KiB
JavaScript
792 lines
43 KiB
JavaScript
|
|
let express = require('express')
|
|
let router = express.Router()
|
|
const auth = require('../lib/auth')
|
|
let multer = require('multer')
|
|
let formidable = require('formidable')
|
|
let cryptoRandomString = require("crypto-random-string");
|
|
let config = require('../config/server.js')
|
|
|
|
const Errors = require('../lib/errors')
|
|
let pagination = require('../lib/pagination')
|
|
let { Ban, Item, Transaction, Inventory, ItemCategory, User, Ip, sequelize, Sequelize } = require('../models')
|
|
let img2 = cryptoRandomString({length: 32})
|
|
const rateLimit = require("express-rate-limit");
|
|
let path = require("path")
|
|
const limiter = rateLimit({
|
|
windowMs: 60 * 1000,
|
|
max: 100,
|
|
message: "{\"errors\":[{\"name\":\"rateLimit\",\"message\":\"You may only make 1 request to this endpoint per minute.\",\"status\":429}]}"
|
|
});
|
|
const storage = multer.diskStorage({
|
|
destination: (req, file, cb) => {
|
|
cb(null, config.rootFolder + '/rendering/global/');
|
|
},
|
|
filename: (req, file, cb) => {
|
|
cb(null, cryptoRandomString({length: 32}) + ".png")
|
|
}
|
|
});
|
|
const storageObj = multer.diskStorage({
|
|
destination: (req, file, cb) => {
|
|
cb(null, config.rootFolder + '/rendering/global/');
|
|
},
|
|
filename: (req, file, cb) => {
|
|
var name = cryptoRandomString({length: 32})
|
|
var name2 = name
|
|
cb(null, name2 + path.extname(file.originalname))
|
|
}
|
|
});
|
|
var uploadObj = multer({
|
|
storage: storageObj,
|
|
});
|
|
var upload = multer({
|
|
storage: storage,
|
|
fileFilter: (req, file, cb) => {
|
|
if (file.mimetype === "image/png") {
|
|
cb(null, true);
|
|
} else {
|
|
cb(null, false);
|
|
return cb(new Error('Only .png is allowed'));
|
|
}
|
|
}
|
|
});
|
|
|
|
router.get('/', async(req, res) => {
|
|
try {
|
|
let categories = await ItemCategory.findAll()
|
|
|
|
res.json(categories)
|
|
} catch (e) {
|
|
res.status(500)
|
|
res.json({
|
|
errors: [Errors.unknown]
|
|
})
|
|
}
|
|
|
|
})
|
|
|
|
router.post('/randomShirt', auth, async(req, res, next) => {
|
|
try {
|
|
if(!req.userData.executive) {
|
|
throw Errors.requestNotAuthorized
|
|
}
|
|
let marketplace = await Item.create({
|
|
name: cryptoRandomString({length: 5}),
|
|
UserId: 1,
|
|
sourceFile: cryptoRandomString({length: 32}),
|
|
previewFile: cryptoRandomString({length: 32}),
|
|
limited: true,
|
|
salePrice: 69,
|
|
saleEnabled: true,
|
|
price: 100,
|
|
quantityAllowed: 69,
|
|
approved: true,
|
|
ItemCategoryId: 2,
|
|
description: cryptoRandomString({length: 32}),
|
|
object: cryptoRandomString({length: 32})
|
|
})
|
|
res.json(marketplace)
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.get('/:category', async(req, res, next) => {
|
|
try {
|
|
let threads, threadsLatestPost, resThreads, user
|
|
let { from } = pagination.getPaginationProps(req.query, true)
|
|
let offset = Number.isInteger(+req.query.offset) ? +req.query.offset : 0;
|
|
console.log(offset)
|
|
let limit = 30
|
|
|
|
if(req.query.username) {
|
|
user = await User.findOne({ where: { username: req.query.username }})
|
|
}
|
|
const Op = Sequelize.Op;
|
|
if(req.query.search) {
|
|
var search = req.query.search
|
|
} else {
|
|
var search = ''
|
|
}
|
|
function threadInclude(order) {
|
|
let options = {
|
|
model: Item,
|
|
order: [['id', order]],
|
|
limit: 30,
|
|
offset: offset,
|
|
subQuery: false,
|
|
where: {deleted: false, approved: true, name: {
|
|
[Op.like]: '%' + search + '%'
|
|
}},
|
|
include: [
|
|
{ model: User, attributes: ['username', 'createdAt', 'id', 'color', 'picture', 'locked', 'admin', 'booster', 'executive', 'bot'] },
|
|
]
|
|
}
|
|
|
|
if(user) {
|
|
options.where.userId = user.id
|
|
}
|
|
|
|
if(from !== null) {
|
|
options.where.id = { $lte: from }
|
|
}
|
|
|
|
return [options]
|
|
}
|
|
if(req.params.category === 'ALL') {
|
|
threads = await Item.findAll( threadInclude('ASC')[0] )
|
|
threadsLatestPost = await Item.findAll( threadInclude('DESC')[0] )
|
|
} else {
|
|
threads = await ItemCategory.findOne({
|
|
where: { value: req.params.category },
|
|
include: threadInclude('DESC')
|
|
})
|
|
}
|
|
if(!threads) {
|
|
throw Errors.invalidCategory
|
|
}
|
|
if(Array.isArray(threads)) {
|
|
resThreads = {
|
|
name: 'All',
|
|
value: 'ALL',
|
|
Threads: threads,
|
|
meta: {}
|
|
}
|
|
|
|
threadsLatestPost = { Threads: threadsLatestPost }
|
|
} else {
|
|
resThreads = threads.toJSON()
|
|
resThreads.meta = {}
|
|
}
|
|
|
|
res.json(resThreads)
|
|
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.get('/view/:id', async(req, res, next) => {
|
|
try {
|
|
let queryObj = {
|
|
where: {id: req.params.id},
|
|
include: { model: User, attributes: ['username', 'description', 'createdAt', 'id', 'color', 'picture', 'locked', 'admin', 'booster', 'executive', 'bot'] }
|
|
}
|
|
let marketplace = await Item.findOne(queryObj)
|
|
if (!marketplace) throw Errors.invalidItem
|
|
if(marketplace.deleted) {
|
|
let queryObj = {
|
|
where: {id: req.params.id},
|
|
attributes: ['name', 'deleted', 'createdAt', 'id', 'updatedAt', 'price'],
|
|
include: { model: User, attributes: ['username', 'description', 'createdAt', 'id', 'color', 'picture', 'locked', 'admin', 'booster', 'executive', 'bot'] }
|
|
}
|
|
let marketplace = await Item.findOne(queryObj)
|
|
res.json({createdAt: marketplace.createdAt, updatedAt: marketplace.createdAt, id: marketplace.id, name: "Item unavailable", deleted: true, price: 0, User: marketplace.User, description: 'Item is currently unavailable at this time.', approved: false})
|
|
}
|
|
if(!marketplace.approved) {
|
|
let queryObj = {
|
|
where: {id: req.params.id},
|
|
attributes: ['name', 'deleted', 'createdAt', 'id', 'updatedAt', 'price'],
|
|
include: { model: User, attributes: ['username', 'createdAt', 'id', 'color', 'picture', 'locked', 'admin', 'booster', 'executive', 'bot'] }
|
|
}
|
|
let marketplace = await Item.findOne(queryObj)
|
|
res.json({createdAt: marketplace.createdAt, updatedAt: marketplace.createdAt, id: marketplace.id, name: "Item is pending admin approval", deleted: false, price: 0, User: marketplace.User, description: 'Item is currently unavailable at this time.', approved: false})
|
|
}
|
|
res.json(marketplace.toJSON())
|
|
} catch (err) { next(err) }
|
|
})
|
|
|
|
router.get('/purchase/:id', auth, async(req, res, next) => {
|
|
await Ban.ReadOnlyMode(req.userData.id)
|
|
try {
|
|
let queryObj = {
|
|
where: {id: req.params.id},
|
|
}
|
|
let queryObj2 = {
|
|
where: {username: req.userData.username},
|
|
}
|
|
let queryObj3 = {
|
|
where: {UserId: req.userData.id, ItemId: req.params.id},
|
|
}
|
|
let marketplace = await Item.findOne(queryObj)
|
|
let user = await User.findOne(queryObj2)
|
|
let inventory = await Inventory.findOne(queryObj3)
|
|
if (!marketplace) throw Errors.invalidItem
|
|
let queryObj4 = {
|
|
where: {id: marketplace.UserId},
|
|
}
|
|
let payUser = await User.findOne(queryObj4)
|
|
if (user.koins < marketplace.price && !marketplace.saleEnabled) {
|
|
throw Errors.insufficientKoins
|
|
}
|
|
if (user.koins < marketplace.salePrice && marketplace.saleEnabled) {
|
|
throw Errors.insufficientKoins
|
|
}
|
|
if (marketplace.offSale) {
|
|
throw Errors.offSale
|
|
}
|
|
if(marketplace.deleted) {
|
|
throw Errors.itemUnavailable
|
|
}
|
|
if(!marketplace.approved) {
|
|
throw Errors.itemUnavailable
|
|
}
|
|
if(inventory && !marketplace.limited) {
|
|
throw Errors.itemOwned
|
|
}
|
|
if(inventory && marketplace.limited) {
|
|
throw Errors.itemOwnedLimited
|
|
}
|
|
if(marketplace.limited && marketplace.purchases === marketplace.quantityAllowed && marketplace.quantityAllowed !== 0) {
|
|
throw Errors.itemUnavailable
|
|
}
|
|
if(marketplace.saleEnabled) {
|
|
const UserId = user.id
|
|
const priceTotal = marketplace.salePrice
|
|
await user.removeKoins(priceTotal)
|
|
await payUser.addKoins(priceTotal)
|
|
await Transaction.create({UserId: payUser.id, priceOfPurchase: priceTotal, text: user.username + ' purchased your Marketplace item, ' + marketplace.name + ' (' + marketplace.id + ') for ' + priceTotal + ' koins, you have been given ' + priceTotal + ' koins. Your Marketplace item was on sale when this transaction was made.', itemId: marketplace.id, limited: marketplace.limited})
|
|
await Transaction.create({UserId: UserId, priceOfPurchase: priceTotal, text: user.username + ' purchased ' + marketplace.name + ' (' + marketplace.id + ') from the Marketplace for ' + priceTotal + ' koins', itemId: marketplace.id, limited: marketplace.limited, ipId: Ip.createIfNotExists(req.ip, user)})
|
|
await marketplace.update({purchases: +1})
|
|
await Inventory.create({UserId: UserId, purchasePrice: priceTotal, isReselling: false, isResellingPrice: 0, ItemId: marketplace.id, boughtFrom: marketplace.UserId, resellType: 0, auctionId: 0})
|
|
res.status(200)
|
|
res.json({success: true})
|
|
} else {
|
|
const UserId = user.id
|
|
const priceTotal = marketplace.price
|
|
await user.removeKoins(priceTotal)
|
|
await payUser.addKoins(priceTotal)
|
|
await Transaction.create({UserId: payUser.id, priceOfPurchase: priceTotal, text: user.username + ' purchased your Marketplace item, ' + marketplace.name + ' (' + marketplace.id + ') for ' + priceTotal + ' koins, you have been given ' + priceTotal + ' koins.', itemId: marketplace.id, limited: marketplace.limited})
|
|
await Transaction.create({UserId: UserId, priceOfPurchase: priceTotal, text: user.username + ' purchased ' + marketplace.name + ' (' + marketplace.id + ') from the Marketplace for ' + priceTotal + ' koins', itemId: marketplace.id, limited: marketplace.limited, ipId: Ip.createIfNotExists(req.ip, user)})
|
|
await marketplace.updatePurchaseCount()
|
|
await Inventory.create({UserId: UserId, purchasePrice: priceTotal, isReselling: false, isResellingPrice: 0, ItemId: marketplace.id, boughtFrom: marketplace.UserId, resellType: 0, auctionId: 0})
|
|
res.status(200)
|
|
res.json({success: true})
|
|
}
|
|
|
|
} catch (err) { next(err) }
|
|
})
|
|
|
|
router.get('/check/:id', auth, async(req, res, next) => {
|
|
try {
|
|
let queryObj = {
|
|
where: {id: req.params.id},
|
|
}
|
|
let queryObj3 = {
|
|
where: {UserId: req.userData.id, ItemId: req.params.id},
|
|
}
|
|
let inventory = await Inventory.findOne(queryObj3)
|
|
let marketplace = await Item.findOne(queryObj)
|
|
if(marketplace) {
|
|
if (inventory) {
|
|
res.status(200)
|
|
res.json({purchased: true})
|
|
} else {
|
|
res.status(200)
|
|
res.json({purchased: false})
|
|
}
|
|
} else {
|
|
throw Errors.invalidItem
|
|
}
|
|
} catch (err) { next(err) }
|
|
})
|
|
|
|
router.put('/rerender/:id', auth, limiter, async (req, res, next) => {
|
|
try {
|
|
let user = await User.findOne({
|
|
where: {id: req.userData.id}
|
|
});
|
|
if(!req.userData.admin) {
|
|
throw Errors.requestNotAuthorized
|
|
}
|
|
if(!user.admin) {
|
|
throw Errors.requestNotAuthorized
|
|
}
|
|
let marketplace = await Item.findOne({
|
|
where: {id: req.params.id}
|
|
});
|
|
if(marketplace) {
|
|
if(marketplace.ItemCategoryId === 0) {
|
|
var type = "hat"
|
|
} else if(marketplace.ItemCategoryId === 1) {
|
|
var type = "face"
|
|
} else if(marketplace.ItemCategoryId === 2) {
|
|
var type = "shirt"
|
|
} else if(marketplace.ItemCategoryId === 3) {
|
|
var type = "pants"
|
|
}
|
|
const { exec } = require('child_process');
|
|
var fs = require("fs");
|
|
let rootPathRender = config.rootFolder + "/";
|
|
var blendFilePath = rootPathRender + "rendering/avatar.blend";
|
|
var img4 = marketplace.previewFile
|
|
var imageSavePath = config.cdnFolder + "/marketplace/avatars/" + img4 + ".png";
|
|
var pythonFilePath = "rendering/marketplacecontent/"+req.userData.id+".py";
|
|
if(marketplace.object) {
|
|
var object = marketplace.object
|
|
} else {
|
|
var object = marketplace.sourceFile
|
|
}
|
|
if(type === "face") {
|
|
var faceFilePath = rootPathRender + "rendering/global/" + marketplace.sourceFile + ".png";
|
|
var shirtFilePath = rootPathRender + "rendering/global/0.png";
|
|
var pantsFilePath = rootPathRender + "rendering/global/0.png";
|
|
var hat = ''
|
|
}
|
|
if(type === "shirt") {
|
|
var faceFilePath = rootPathRender + "rendering/global/defaultFace.png";
|
|
var shirtFilePath = rootPathRender + "rendering/global/" + marketplace.sourceFile + ".png"; // should be set to 0 by default, 0.png will just be a transparent image
|
|
var pantsFilePath = rootPathRender + "rendering/global/0.png";
|
|
var hat = ''
|
|
}
|
|
if(type === "pants") {
|
|
var faceFilePath = rootPathRender + "rendering/global/defaultFace.png";
|
|
var shirtFilePath = rootPathRender + "rendering/global/0.png";
|
|
var hat = ''
|
|
var pantsFilePath = rootPathRender + "rendering/global/" + marketplace.sourceFile + ".png"; // should be set to 0 by default, 0.png will just be a transparent image
|
|
}
|
|
if(type === "hat") {
|
|
var faceFilePath = rootPathRender + "rendering/global/defaultFace.png";
|
|
var shirtFilePath = rootPathRender + "rendering/global/0.png";
|
|
var pantsFilePath = rootPathRender + "rendering/global/0.png";
|
|
var hatFilePath = rootPathRender + "rendering/global/" + object
|
|
var hat = "hat_import = bpy.ops.import_scene.obj(filepath='"+hatFilePath+"')\nhat = bpy.context.selected_objects[0]\nbpy.context.selected_objects[0].data.name = 'hat'\nbpy.context.selected_objects[0].name = 'hat'\nhat_material = bpy.data.materials.new('hat')\nhat_material.diffuse_shader = 'LAMBERT'\nhat.active_material = hat_material\nhat_image = bpy.data.images.load(filepath = '" + rootPathRender + "rendering/global/"+marketplace.sourceFile+"')\nhat_texture = bpy.data.textures.new('ColorTex', type = 'IMAGE')\nhat_texture.image = hat_image\nhat_add = bpy.data.objects['hat'].active_material.texture_slots.add()\nhat_add.texture = hat_texture";
|
|
}
|
|
|
|
var imports = "import bpy";
|
|
var functions = "def hex_to_rgb(value):\n gamma = 2.05\n value = value.lstrip('#')\n lv = len(value)\n fin = list(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3))\n r = pow(fin[0] / 255, gamma)\n g = pow(fin[1] / 255, gamma)\n b = pow(fin[2] / 255, gamma)\n fin.clear()\n fin.append(r)\n fin.append(g)\n fin.append(b)\n return tuple(fin)";
|
|
var blenderImport = "bpy.ops.wm.open_mainfile(filepath='"+blendFilePath+"')";
|
|
var headColor = "bpy.data.objects['Head'].select = True\nbpy.data.materials['Head'].diffuse_color = hex_to_rgb('#ffffff')\nbpy.data.materials['Face'].diffuse_color = hex_to_rgb('#ffffff')";
|
|
var leftArmColor = "bpy.data.objects['Left Arm'].select = True\nbpy.data.objects['Left Arm'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var rightArmColor = "bpy.data.objects['Right Arm'].select = True\nbpy.data.objects['Right Arm'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var bodyColor = "bpy.data.objects['Torso'].select = True\nbpy.data.objects['Torso'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var leftLegColor = "bpy.data.objects['Left Leg'].select = True\nbpy.data.objects['Left Leg'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var rightLegColor = "bpy.data.objects['Right Leg'].select = True\nbpy.data.objects['Right Leg'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var colors = headColor+"\n"+leftArmColor+"\n"+bodyColor+"\n"+rightArmColor+"\n"+leftLegColor+"\n"+rightLegColor;
|
|
|
|
var face = "face_Image = bpy.data.images.load(filepath = '"+faceFilePath+"')\nbpy.data.textures['Face'].image = face_Image";
|
|
var shirt = "shirt_Image = bpy.data.images.load(filepath = '"+shirtFilePath+"')\nbpy.data.textures['Shirt'].image = shirt_Image\nbpy.data.textures['ShirtR'].image = shirt_Image\nbpy.data.textures['ShirtL'].image = shirt_Image";
|
|
var pants = "pants_Image = bpy.data.images.load(filepath = '"+pantsFilePath+"')\nbpy.data.textures['PantsR'].image = pants_Image\nbpy.data.textures['PantsL'].image = pants_Image";
|
|
var render = "for obj in bpy.data.objects:\n obj.select = False\n bpy.ops.object.select_all(action='SELECT')\nbpy.ops.view3d.camera_to_view_selected()\nscene = bpy.context.scene\nscene.render.image_settings.file_format = 'PNG'\nscene.render.filepath = '"+imageSavePath+"'\nbpy.ops.render.render(write_still = 1)";
|
|
var python = imports+"\n"+functions+"\n"+blenderImport+"\n"+colors+"\n"+hat+"\n"+face+"\n"+shirt+"\n"+pants+"\n"+render;
|
|
fs.writeFile("rendering/marketplacecontent/"+marketplace.id+".py", python, function(err,data){
|
|
if(err) { console.log(err) }
|
|
})
|
|
exec("blender -b -P rendering/marketplacecontent/"+marketplace.id+".py", (err, stdout, stderr) => {
|
|
if(err) { console.log(err) }
|
|
console.log("stdout: " + stdout);
|
|
console.log("stderr: " + stderr);
|
|
res.status(200)
|
|
res.json(marketplace.toJSON())
|
|
});
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
router.post('/upload/0', auth, uploadObj.fields([{
|
|
name: 'image', maxCount: 1
|
|
}, {
|
|
name: 'fileObj', maxCount: 1
|
|
}]), limiter, async (req, res, next) => {
|
|
try {
|
|
let findCategory = await ItemCategory.findOne({
|
|
where: {id: 0}
|
|
});
|
|
console.log(findCategory.id)
|
|
if(!findCategory) {
|
|
throw Errors.marketplaceNotFound
|
|
}
|
|
let user = await User.findOne({
|
|
where: {id: req.userData.id}
|
|
});
|
|
if(!user.modeler) {
|
|
throw Errors.requestNotAuthorized
|
|
}
|
|
|
|
if(findCategory.locked && !user.modeler) {
|
|
throw Errors.marketplaceAdminOnly
|
|
}
|
|
if(req.body.limited === true && !user.modeler) {
|
|
throw Errors.marketplaceAdminOnly
|
|
}
|
|
if(req.body.price < 0) {
|
|
throw Errors.underPriced
|
|
}
|
|
if(req.body.onSalePrice < 0) {
|
|
throw Errors.underPriced
|
|
}
|
|
if(findCategory) {
|
|
let img3 = cryptoRandomString({length: 32})
|
|
let img4 = img3
|
|
let marketplace = await Item.create({
|
|
name: req.body.name,
|
|
UserId: user.id,
|
|
sourceFile: req.files.image[0].filename,
|
|
previewFile: img4,
|
|
limited: req.body.limited,
|
|
salePrice: req.body.onSalePrice,
|
|
saleEnabled: req.body.onSale,
|
|
price: req.body.price,
|
|
quantityAllowed: req.body.quantityAllowed,
|
|
approved: true,
|
|
ItemCategoryId: findCategory.id,
|
|
description: req.body.description,
|
|
object: req.files.fileObj[0].filename
|
|
})
|
|
if(marketplace.ItemCategoryId === 0) {
|
|
var type = "hat"
|
|
} else if(marketplace.ItemCategoryId === 1) {
|
|
var type = "face"
|
|
} else if(marketplace.ItemCategoryId === 2) {
|
|
var type = "shirt"
|
|
} else if(marketplace.ItemCategoryId === 3) {
|
|
var type = "pants"
|
|
}
|
|
const { exec } = require('child_process');
|
|
var fs = require("fs");
|
|
let rootPathRender = config.rootFolder + "/";
|
|
var blendFilePath = rootPathRender + "rendering/avatar.blend";
|
|
var imageSavePath = config.cdnFolder + "/marketplace/avatars/" + img4 + ".png";
|
|
var pythonFilePath = "rendering/marketplacecontent/"+req.userData.id+".py";
|
|
if(marketplace.object) {
|
|
var object = marketplace.object
|
|
} else {
|
|
var object = marketplace.sourceFile
|
|
}
|
|
if(type === "face") {
|
|
var faceFilePath = rootPathRender + "rendering/global/" + marketplace.sourceFile + ".png";
|
|
var shirtFilePath = rootPathRender + "rendering/global/0.png";
|
|
var pantsFilePath = rootPathRender + "rendering/global/0.png";
|
|
var hat = ''
|
|
}
|
|
if(type === "shirt") {
|
|
var faceFilePath = rootPathRender + "rendering/global/defaultFace.png";
|
|
var shirtFilePath = rootPathRender + "rendering/global/" + marketplace.sourceFile + ".png"; // should be set to 0 by default, 0.png will just be a transparent image
|
|
var pantsFilePath = rootPathRender + "rendering/global/0.png";
|
|
var hat = ''
|
|
}
|
|
if(type === "pants") {
|
|
var faceFilePath = rootPathRender + "rendering/global/defaultFace.png";
|
|
var shirtFilePath = rootPathRender + "rendering/global/0.png";
|
|
var hat = ''
|
|
var pantsFilePath = rootPathRender + "rendering/global/" + marketplace.sourceFile + ".png"; // should be set to 0 by default, 0.png will just be a transparent image
|
|
}
|
|
if(type === "hat") {
|
|
var faceFilePath = rootPathRender + "rendering/global/defaultFace.png";
|
|
var shirtFilePath = rootPathRender + "rendering/global/0.png";
|
|
var pantsFilePath = rootPathRender + "rendering/global/0.png";
|
|
var hatFilePath = rootPathRender + "rendering/global/" + object
|
|
var hat = "hat_import = bpy.ops.import_scene.obj(filepath='"+hatFilePath+"')\nhat = bpy.context.selected_objects[0]\nbpy.context.selected_objects[0].data.name = 'hat'\nbpy.context.selected_objects[0].name = 'hat'\nhat_material = bpy.data.materials.new('hat')\nhat_material.diffuse_shader = 'LAMBERT'\nhat.active_material = hat_material\nhat_image = bpy.data.images.load(filepath = '" + rootPathRender + "rendering/global/"+marketplace.sourceFile+"')\nhat_texture = bpy.data.textures.new('ColorTex', type = 'IMAGE')\nhat_texture.image = hat_image\nhat_add = bpy.data.objects['hat'].active_material.texture_slots.add()\nhat_add.texture = hat_texture";
|
|
}
|
|
|
|
var imports = "import bpy";
|
|
var functions = "def hex_to_rgb(value):\n gamma = 2.05\n value = value.lstrip('#')\n lv = len(value)\n fin = list(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3))\n r = pow(fin[0] / 255, gamma)\n g = pow(fin[1] / 255, gamma)\n b = pow(fin[2] / 255, gamma)\n fin.clear()\n fin.append(r)\n fin.append(g)\n fin.append(b)\n return tuple(fin)";
|
|
var blenderImport = "bpy.ops.wm.open_mainfile(filepath='"+blendFilePath+"')";
|
|
var headColor = "bpy.data.objects['Head'].select = True\nbpy.data.materials['Head'].diffuse_color = hex_to_rgb('#ffffff')\nbpy.data.materials['Face'].diffuse_color = hex_to_rgb('#ffffff')";
|
|
var leftArmColor = "bpy.data.objects['Left Arm'].select = True\nbpy.data.objects['Left Arm'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var rightArmColor = "bpy.data.objects['Right Arm'].select = True\nbpy.data.objects['Right Arm'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var bodyColor = "bpy.data.objects['Torso'].select = True\nbpy.data.objects['Torso'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var leftLegColor = "bpy.data.objects['Left Leg'].select = True\nbpy.data.objects['Left Leg'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var rightLegColor = "bpy.data.objects['Right Leg'].select = True\nbpy.data.objects['Right Leg'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var colors = headColor+"\n"+leftArmColor+"\n"+bodyColor+"\n"+rightArmColor+"\n"+leftLegColor+"\n"+rightLegColor;
|
|
|
|
var face = "face_Image = bpy.data.images.load(filepath = '"+faceFilePath+"')\nbpy.data.textures['Face'].image = face_Image";
|
|
var shirt = "shirt_Image = bpy.data.images.load(filepath = '"+shirtFilePath+"')\nbpy.data.textures['Shirt'].image = shirt_Image\nbpy.data.textures['ShirtR'].image = shirt_Image\nbpy.data.textures['ShirtL'].image = shirt_Image";
|
|
var pants = "pants_Image = bpy.data.images.load(filepath = '"+pantsFilePath+"')\nbpy.data.textures['PantsR'].image = pants_Image\nbpy.data.textures['PantsL'].image = pants_Image";
|
|
var render = "for obj in bpy.data.objects:\n obj.select = False\n bpy.ops.object.select_all(action='SELECT')\nbpy.ops.view3d.camera_to_view_selected()\nscene = bpy.context.scene\nscene.render.image_settings.file_format = 'PNG'\nscene.render.filepath = '"+imageSavePath+"'\nbpy.ops.render.render(write_still = 1)";
|
|
var python = imports+"\n"+functions+"\n"+blenderImport+"\n"+colors+"\n"+hat+"\n"+face+"\n"+shirt+"\n"+pants+"\n"+render;
|
|
fs.writeFile("rendering/marketplacecontent/"+marketplace.id+".py", python, function(err,data){
|
|
if(err) { console.log(err) }
|
|
})
|
|
await Inventory.create({UserId: req.userData.id, purchasePrice: 0, isReselling: false, isResellingPrice: 0, ItemId: marketplace.id, boughtFrom: marketplace.UserId, resellType: 0, auctionId: 0})
|
|
exec("blender -b -P rendering/marketplacecontent/"+marketplace.id+".py", (err, stdout, stderr) => {
|
|
if(err) { console.log(err) }
|
|
console.log("stdout: " + stdout);
|
|
console.log("stderr: " + stderr);
|
|
res.status(200)
|
|
res.json(marketplace.toJSON())
|
|
});
|
|
} else {
|
|
throw Errors.marketplaceNotFound
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.post('/preview/0', auth, uploadObj.fields([{
|
|
name: 'image', maxCount: 1
|
|
}, {
|
|
name: 'fileObj', maxCount: 1
|
|
}]), limiter, async (req, res, next) => {
|
|
if(!req.userData.admin) {
|
|
throw Errors.requestNotAuthorized
|
|
}
|
|
let rando = cryptoRandomString({type: "numeric", length: 64})
|
|
var rand = rando
|
|
let type = 'hat'
|
|
const { exec } = require('child_process');
|
|
var fs = require("fs");
|
|
let rootPathRender = config.rootFolder + "/";
|
|
var blendFilePath = rootPathRender + "rendering/avatar.blend";
|
|
var imageSavePath = config.cdnFolder + "/marketplace/preview/" + rand + ".png";
|
|
var pythonFilePath = "rendering/preview/"+rand+".py";
|
|
var object = req.files.fileObj[0].filename
|
|
|
|
if(type === "hat") {
|
|
var faceFilePath = rootPathRender + "rendering/global/defaultFace.png";
|
|
var shirtFilePath = rootPathRender + "rendering/global/0.png";
|
|
var pantsFilePath = rootPathRender + "rendering/global/0.png";
|
|
var hatFilePath = rootPathRender + "rendering/global/" + object
|
|
var hat = "hat_import = bpy.ops.import_scene.obj(filepath='"+hatFilePath+"')\nhat = bpy.context.selected_objects[0]\nbpy.context.selected_objects[0].data.name = 'hat'\nbpy.context.selected_objects[0].name = 'hat'\nhat_material = bpy.data.materials.new('hat')\nhat_material.diffuse_shader = 'LAMBERT'\nhat.active_material = hat_material\nhat_image = bpy.data.images.load(filepath = '" + rootPathRender + "rendering/global/"+req.files.image[0].filename+"')\nhat_texture = bpy.data.textures.new('ColorTex', type = 'IMAGE')\nhat_texture.image = hat_image\nhat_add = bpy.data.objects['hat'].active_material.texture_slots.add()\nhat_add.texture = hat_texture";
|
|
}
|
|
|
|
var imports = "import bpy";
|
|
var functions = "def hex_to_rgb(value):\n gamma = 2.05\n value = value.lstrip('#')\n lv = len(value)\n fin = list(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3))\n r = pow(fin[0] / 255, gamma)\n g = pow(fin[1] / 255, gamma)\n b = pow(fin[2] / 255, gamma)\n fin.clear()\n fin.append(r)\n fin.append(g)\n fin.append(b)\n return tuple(fin)";
|
|
var blenderImport = "bpy.ops.wm.open_mainfile(filepath='"+blendFilePath+"')";
|
|
var headColor = "bpy.data.objects['Head'].select = True\nbpy.data.materials['Head'].diffuse_color = hex_to_rgb('#ffffff')\nbpy.data.materials['Face'].diffuse_color = hex_to_rgb('#ffffff')";
|
|
var leftArmColor = "bpy.data.objects['Left Arm'].select = True\nbpy.data.objects['Left Arm'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var rightArmColor = "bpy.data.objects['Right Arm'].select = True\nbpy.data.objects['Right Arm'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var bodyColor = "bpy.data.objects['Torso'].select = True\nbpy.data.objects['Torso'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var leftLegColor = "bpy.data.objects['Left Leg'].select = True\nbpy.data.objects['Left Leg'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var rightLegColor = "bpy.data.objects['Right Leg'].select = True\nbpy.data.objects['Right Leg'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var colors = headColor+"\n"+leftArmColor+"\n"+bodyColor+"\n"+rightArmColor+"\n"+leftLegColor+"\n"+rightLegColor;
|
|
|
|
var face = "face_Image = bpy.data.images.load(filepath = '"+faceFilePath+"')\nbpy.data.textures['Face'].image = face_Image";
|
|
var shirt = "shirt_Image = bpy.data.images.load(filepath = '"+shirtFilePath+"')\nbpy.data.textures['Shirt'].image = shirt_Image\nbpy.data.textures['ShirtR'].image = shirt_Image\nbpy.data.textures['ShirtL'].image = shirt_Image";
|
|
var pants = "pants_Image = bpy.data.images.load(filepath = '"+pantsFilePath+"')\nbpy.data.textures['PantsR'].image = pants_Image\nbpy.data.textures['PantsL'].image = pants_Image";
|
|
var render = "for obj in bpy.data.objects:\n obj.select = False\n bpy.ops.object.select_all(action='SELECT')\nbpy.ops.view3d.camera_to_view_selected()\nscene = bpy.context.scene\nscene.render.image_settings.file_format = 'PNG'\nscene.render.filepath = '"+imageSavePath+"'\nbpy.ops.render.render(write_still = 1)";
|
|
var python = imports+"\n"+functions+"\n"+blenderImport+"\n"+colors+"\n"+hat+"\n"+face+"\n"+shirt+"\n"+pants+"\n"+render;
|
|
fs.writeFile("rendering/preview/"+rand+".py", python, function(err,data){
|
|
if(err) { console.log(err) }
|
|
})
|
|
exec("blender -b -P rendering/preview/"+rand+".py", (err, stdout, stderr) => {
|
|
if(err) { console.log(err) }
|
|
console.log("stdout: " + stdout);
|
|
console.log("stderr: " + stderr);
|
|
res.status(200)
|
|
res.json({image: rand})
|
|
});
|
|
})
|
|
|
|
router.post('/upload/:id', auth, limiter, async (req, res, next) => {
|
|
try {
|
|
let form = new formidable.IncomingForm();
|
|
let crs = cryptoRandomString({length: 32})
|
|
let img = crs
|
|
|
|
form.parse(req);
|
|
form.keepExtensions = true;
|
|
form.multiples = true;
|
|
console.log(form)
|
|
let findCategory = await ItemCategory.findOne({
|
|
where: {id: req.params.id}
|
|
});
|
|
console.log(findCategory.id)
|
|
if(!findCategory) {
|
|
throw Errors.marketplaceNotFound
|
|
}
|
|
let user = await User.findOne({
|
|
where: {id: req.userData.id}
|
|
});
|
|
|
|
if(findCategory.locked && !user.modeler) {
|
|
throw Errors.marketplaceAdminOnly
|
|
}
|
|
if(req.body.limited === true && !user.modeler) {
|
|
throw Errors.marketplaceAdminOnly
|
|
}
|
|
if(req.body.price < 0) {
|
|
throw Errors.underPriced
|
|
}
|
|
if(req.body.onSalePrice < 0) {
|
|
throw Errors.underPriced
|
|
}
|
|
if(findCategory) {
|
|
let img3 = cryptoRandomString({length: 32})
|
|
let img4 = img3
|
|
console.log(storage)
|
|
if(req.userData.admin) {
|
|
form.on('fileBegin', function (name, image, field){
|
|
image.path = config.rootFolder + '/rendering/global/' + img + image.name.match(/\.[0-9a-z]+$/i);
|
|
console.log(field)
|
|
});
|
|
form.on('file', function (name, file, field){
|
|
console.log('Uploaded File (Hat API) ' + file.name);
|
|
console.log(field)
|
|
});
|
|
var marketplace = await Item.create({
|
|
name: req.body.name,
|
|
UserId: user.id,
|
|
sourceFile: 'tired',
|
|
previewFile: img4,
|
|
limited: req.body.limited,
|
|
salePrice: req.body.onSalePrice,
|
|
saleEnabled: req.body.onSale,
|
|
price: req.body.price,
|
|
quantityAllowed: req.body.quantityAllowed,
|
|
approved: false,
|
|
ItemCategoryId: findCategory.id,
|
|
description: req.body.description
|
|
})
|
|
} else {
|
|
var marketplace = await Item.create({
|
|
name: req.body.name,
|
|
UserId: user.id,
|
|
sourceFile: req.file.filename,
|
|
previewFile: img4,
|
|
limited: false,
|
|
salePrice: req.body.onSalePrice,
|
|
saleEnabled: req.body.onSale,
|
|
price: req.body.price,
|
|
quantityAllowed: 0,
|
|
approved: false,
|
|
ItemCategoryId: findCategory.id,
|
|
description: req.body.description
|
|
})
|
|
}
|
|
if(marketplace.ItemCategoryId === 0) {
|
|
var type = "hat"
|
|
} else if(marketplace.ItemCategoryId === 1) {
|
|
var type = "face"
|
|
} else if(marketplace.ItemCategoryId === 2) {
|
|
var type = "shirt"
|
|
} else if(marketplace.ItemCategoryId === 3) {
|
|
var type = "pants"
|
|
}
|
|
const { exec } = require('child_process');
|
|
var fs = require("fs");
|
|
let rootPathRender = config.rootFolder + "/";
|
|
var blendFilePath = rootPathRender + "rendering/avatar.blend";
|
|
var imageSavePath = config.cdnFolder + "/marketplace/avatars/" + img4 + ".png";
|
|
var pythonFilePath = "rendering/marketplacecontent/"+req.userData.id+".py";
|
|
if(type === "face") {
|
|
var faceFilePath = rootPathRender + "rendering/global/" + marketplace.sourceFile;
|
|
var shirtFilePath = rootPathRender + "rendering/global/0.png";
|
|
var pantsFilePath = rootPathRender + "rendering/global/0.png";
|
|
var hat = ''
|
|
}
|
|
if(type === "shirt") {
|
|
var faceFilePath = rootPathRender + "rendering/global/defaultFace.png";
|
|
var shirtFilePath = rootPathRender + "rendering/global/" + marketplace.sourceFile; // should be set to 0 by default, 0.png will just be a transparent image
|
|
var pantsFilePath = rootPathRender + "rendering/global/0.png";
|
|
var hat = ''
|
|
}
|
|
if(type === "pants") {
|
|
var faceFilePath = rootPathRender + "rendering/global/defaultFace.png";
|
|
var shirtFilePath = rootPathRender + "rendering/global/0.png";
|
|
var hat = ''
|
|
var pantsFilePath = rootPathRender + "rendering/global/" + marketplace.sourceFile; // should be set to 0 by default, 0.png will just be a transparent image
|
|
}
|
|
if(type === "hat") {
|
|
var faceFilePath = rootPathRender + "rendering/global/defaultFace.png";
|
|
var shirtFilePath = rootPathRender + "rendering/global/0.png";
|
|
var pantsFilePath = rootPathRender + "rendering/global/0.png";
|
|
var hatFilePath = rootPathRender + "rendering/global/" + marketplace.sourceFile + ".obj"
|
|
var hat = "hat_import = bpy.ops.import_scene.obj(filepath='"+hatFilePath+"')\nhat = bpy.context.selected_objects[0]\nbpy.context.selected_objects[0].data.name = 'hat'\nbpy.context.selected_objects[0].name = 'hat'\nhat_material = bpy.data.materials.new('hat')\nhat_material.diffuse_shader = 'LAMBERT'\nhat.active_material = hat_material\nhat_image = bpy.data.images.load(filepath = '" + rootPathRender + "rendering/global/"+marketplace.sourceFile+".png')\nhat_texture = bpy.data.textures.new('ColorTex', type = 'IMAGE')\nhat_texture.image = hat_image\nhat_add = bpy.data.objects['hat'].active_material.texture_slots.add()\nhat_add.texture = hat_texture";
|
|
}
|
|
|
|
var imports = "import bpy";
|
|
var functions = "def hex_to_rgb(value):\n gamma = 2.05\n value = value.lstrip('#')\n lv = len(value)\n fin = list(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3))\n r = pow(fin[0] / 255, gamma)\n g = pow(fin[1] / 255, gamma)\n b = pow(fin[2] / 255, gamma)\n fin.clear()\n fin.append(r)\n fin.append(g)\n fin.append(b)\n return tuple(fin)";
|
|
var blenderImport = "bpy.ops.wm.open_mainfile(filepath='"+blendFilePath+"')";
|
|
var headColor = "bpy.data.objects['Head'].select = True\nbpy.data.materials['Head'].diffuse_color = hex_to_rgb('#ffffff')\nbpy.data.materials['Face'].diffuse_color = hex_to_rgb('#ffffff')";
|
|
var leftArmColor = "bpy.data.objects['Left Arm'].select = True\nbpy.data.objects['Left Arm'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var rightArmColor = "bpy.data.objects['Right Arm'].select = True\nbpy.data.objects['Right Arm'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var bodyColor = "bpy.data.objects['Torso'].select = True\nbpy.data.objects['Torso'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var leftLegColor = "bpy.data.objects['Left Leg'].select = True\nbpy.data.objects['Left Leg'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var rightLegColor = "bpy.data.objects['Right Leg'].select = True\nbpy.data.objects['Right Leg'].active_material.diffuse_color = hex_to_rgb('#ffffff')";
|
|
var colors = headColor+"\n"+leftArmColor+"\n"+bodyColor+"\n"+rightArmColor+"\n"+leftLegColor+"\n"+rightLegColor;
|
|
|
|
var face = "face_Image = bpy.data.images.load(filepath = '"+faceFilePath+"')\nbpy.data.textures['Face'].image = face_Image";
|
|
var shirt = "shirt_Image = bpy.data.images.load(filepath = '"+shirtFilePath+"')\nbpy.data.textures['Shirt'].image = shirt_Image\nbpy.data.textures['ShirtR'].image = shirt_Image\nbpy.data.textures['ShirtL'].image = shirt_Image";
|
|
var pants = "pants_Image = bpy.data.images.load(filepath = '"+pantsFilePath+"')\nbpy.data.textures['PantsR'].image = pants_Image\nbpy.data.textures['PantsL'].image = pants_Image";
|
|
var render = "for obj in bpy.data.objects:\n obj.select = False\n bpy.ops.object.select_all(action='SELECT')\nbpy.ops.view3d.camera_to_view_selected()\nscene = bpy.context.scene\nscene.render.image_settings.file_format = 'PNG'\nscene.render.filepath = '"+imageSavePath+"'\nbpy.ops.render.render(write_still = 1)";
|
|
var python = imports+"\n"+functions+"\n"+blenderImport+"\n"+colors+"\n"+hat+"\n"+face+"\n"+shirt+"\n"+pants+"\n"+render;
|
|
fs.writeFile("rendering/marketplacecontent/"+marketplace.id+".py", python, function(err,data){
|
|
if(err) { console.log(err) }
|
|
})
|
|
await Inventory.create({UserId: req.userData.id, purchasePrice: 0, isReselling: false, isResellingPrice: 0, ItemId: marketplace.id, boughtFrom: marketplace.UserId, resellType: 0, auctionId: 0})
|
|
exec("blender -b -P rendering/marketplacecontent/"+marketplace.id+".py", (err, stdout, stderr) => {
|
|
if(err) { console.log(err) }
|
|
console.log("stdout: " + stdout);
|
|
console.log("stderr: " + stderr);
|
|
res.status(200)
|
|
res.json(marketplace.toJSON())
|
|
});
|
|
} else {
|
|
throw Errors.marketplaceNotFound
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.put('/apply/:id', auth, async (req, res, next) => {
|
|
try {
|
|
let item = await Inventory.findOne({
|
|
where: {ItemId: req.params.id, UserId: req.userData.id}
|
|
});
|
|
if (item) {
|
|
let marketplaceItem = await Item.findOne({
|
|
where: {id: item.ItemId}
|
|
})
|
|
if (marketplaceItem) {
|
|
if(!marketplaceItem.approved) {
|
|
throw Errors.itemUnavailable
|
|
}
|
|
if (marketplaceItem.ItemCategoryId === 0) {
|
|
await User.update({ hatId: marketplaceItem.id }, {where: {id: req.userData.id}})
|
|
res.json({success: true})
|
|
} else if (marketplaceItem.ItemCategoryId === 1) {
|
|
await User.update({ faceId: marketplaceItem.id }, {where: {id: req.userData.id}})
|
|
res.json({success: true})
|
|
} else if (marketplaceItem.ItemCategoryId === 2) {
|
|
await User.update({ shirtId: marketplaceItem.id }, {where: {id: req.userData.id}})
|
|
res.json({success: true})
|
|
} else if (marketplaceItem.ItemCategoryId === 3) {
|
|
await User.update({ pantsId: marketplaceItem.id }, {where: {id: req.userData.id}})
|
|
res.json({success: true})
|
|
} else {
|
|
throw Errors.unknown
|
|
}
|
|
} else {
|
|
console.log('second to last')
|
|
throw Errors.unowned
|
|
}
|
|
} else {
|
|
console.log('last')
|
|
throw Errors.unowned
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.put('/remove/:id', auth, async (req, res, next) => {
|
|
try {
|
|
let item = await Inventory.findOne({
|
|
where: {ItemId: req.params.id, UserId: req.userData.id}
|
|
});
|
|
if (item) {
|
|
let marketplaceItem = await Item.findOne({
|
|
where: {id: item.ItemId}
|
|
})
|
|
if (marketplaceItem) {
|
|
console.log(marketplaceItem)
|
|
if (marketplaceItem.ItemCategoryId === 0) {
|
|
await User.update({ hatId: null }, {where: {id: req.userData.id}})
|
|
res.json({success: true})
|
|
} else if (marketplaceItem.ItemCategoryId === 1) {
|
|
await User.update({ faceId: null }, {where: {id: req.userData.id}})
|
|
res.json({success: true})
|
|
} else if (marketplaceItem.ItemCategoryId === 2) {
|
|
await User.update({ shirtId: null }, {where: {id: req.userData.id}})
|
|
res.json({success: true})
|
|
} else if (marketplaceItem.ItemCategoryId === 3) {
|
|
await User.update({ pantsId: null }, {where: {id: req.userData.id}})
|
|
res.json({success: true})
|
|
} else {
|
|
throw Errors.unknown
|
|
}
|
|
} else {
|
|
console.log('second to last')
|
|
throw Errors.unowned
|
|
}
|
|
} else {
|
|
console.log('last')
|
|
throw Errors.unowned
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
module.exports = router
|