const multer = require("multer"); const upload = require("express").Router(); const { exec } = require("child_process"); const { mkdir, readdir, readFile } = require("fs"); const { homedir } = require("os"); const { join } = require("path"); const aws = require("aws-sdk"); const multerS3 = require("multer-s3"); const config = require('./config'); const axios = require('axios'); const spacesEndpoint = new aws.Endpoint("sgp1.digitaloceanspaces.com"); const s3 = new aws.S3({ endpoint: spacesEndpoint }); const temp = `${homedir()}/temp`; const updateStatus = (urlType,courseId=null, chapterId=null, property,status,roomId=null) =>{ axios({ method:'put', url:`${config.server}/${urlType}/upload`, data:{ courseId:courseId, chapterId:chapterId, [property]:status, roomId:roomId }, headers:{ 'Authorization':'yezicoco' } }) .then((res) => { console.log(res.data) }) .catch((err) => { console.log(err) }) } const updateDBdata = (urlType,payload) => { //params //urlType: chapter or curriculum axios({ method:'put', url:`${config.server}/${urlType}/upload`, data:payload, headers:{ 'Authorization':'yezicoco' } }) .then((res)=>{ console.log(res.data) }) .catch((err)=>{ console.log(err) }) } const queryLastIndex = (urlType, chapterId,property) => new Promise(function(resolve, reject){ axios({ method:'get', url:`${config.server}/${urlType}/pre/id/${chapterId}`, headers:{ 'Authorization':'yezicoco' } }) .then((res)=>{ resolve(res.data[property].length) }) .catch((err)=>{ console.log(err) }) }) const queryLatestData = (urlType, chapterId, property) => new Promise ((resolve, reject) => { axios({ method:'get', url:`${config.server}/${urlType}/pre/id/${chapterId}`, headers:{ 'Authorization':'yezicoco' } }) .then((res)=>{ resolve(res.data[property]) }) .catch((err)=>{ console.log(err) }) }) const generatorMultipleArray = (courseId, chapterId, type,length,format='',filename='') =>{ let arr = []; let baseUrl = `https://ccrb-cs.sgp1.digitaloceanspaces.com/course/${courseId}/${type}/${chapterId}/${chapterId}_` for(let index = 1 ; index <= length;index++){ arr.push(baseUrl+index+'.'+format + filename); } return arr; }; const generatorRoomMultipleArray = (roomId, type,length,format='',filename='') =>{ let arr = []; let baseUrl = `https://ccrb-cs.sgp1.digitaloceanspaces.com/room/${roomId}/${type}/${roomId}_` for(let index = 1 ; index <= length;index++){ arr.push(baseUrl+index+'.'+format + filename); } return arr; }; const uploadAttachment2space = () => multer({ storage: multerS3({ s3: s3, bucket: (req, file, cb) => { cb(null, `ccrb-cs/course/${req.body.courseId}/attachments/${req.body.chapterId}`); }, acl: "public-read", key: function(req, file, cb) { cb(null,file.originalname); } }) }); const uploadFile2Space = (type,category) =>{ if(category === 'course'){ return (course, bucket='', dir, file) => new Promise((resovle, reject) => { const params = { Bucket: `ccrb-cs/course/${course}/${type}${bucket?'/':''}${bucket}`, Key: `${file}`, ACL: "public-read" }; readFile(`${dir}/${file}`, (err, buf) => { if (err) return console.error(err); params.Body = buf; s3.putObject(params, (err,data) => { if (err) { console.error(err); return reject(err); }else{ let response = { status:200, url:`${config.space}/course/${course}/${type}${bucket?'/':''}${bucket}/${file}`, } return resovle(response); } }); }); }) }else if(category === 'room'){ return (roomId, bucket='', dir, file) => new Promise((resovle, reject) => { const params = { Bucket: `ccrb-cs/room/${roomId}/${type}${bucket?'/':''}${bucket}`, Key: `${file}`, ACL: "public-read" }; readFile(`${dir}/${file}`, (err, buf) => { if (err) return console.error(err); params.Body = buf; s3.putObject(params, (err,data) => { if (err) { console.error(err); return reject(err); }else{ let response = { status:200, url:`${config.space}/room/${roomId}/${type}${bucket?'/':''}${bucket}/${file}`, } return resovle(response); } }); }); }) } }; //course const slide2SpacePromise = uploadFile2Space('slides','course'); const clip2SpacePromise = uploadFile2Space('clips','course'); const thumb2SpacePromise = uploadFile2Space('thumbs','course'); const cover2SpacePromise = uploadFile2Space('covers','course'); const demo2SpacePromise = uploadFile2Space('demos','course'); //pdf const roomSlide2SpacePromise = uploadFile2Space('slides','room'); const uploadPdf2Server = () => multer({ storage: multer.diskStorage({ destination: (req, file, cb) => { const filename = req.body.roomId? req.body.roomId:req.body.chapterId; const dir = `${temp}/pdf/${filename}`; mkdir(dir, { recursive: true }, () => cb(null, dir)); }, filename: (req, file, cb) => { const filename = req.body.roomId? req.body.roomId:req.body.chapterId; return cb(null, `${filename}.pdf`) } }) }); const runBash = command => new Promise((resovle, reject) => { exec(command, (err,stdout, stderr) => err? reject(err): resovle(stdout)); }); const uploadJpg2Space = (courseId, chapterId, dir, files, index,bashmsg,category) => {if(category === 'course'){ slide2SpacePromise(courseId, chapterId, dir, files[index]) .then((res) => { delete files[index]; if (Object.keys(files).length === 0) { console.log(bashmsg); let pages = bashmsg.slice(bashmsg.indexOf('Total pages: ')+13); let slides = generatorMultipleArray(courseId, chapterId, 'slides', pages, 'jpg'); updateDBdata('chapter',{courseId:courseId,chapterId:chapterId,slideUrl:slides}) exec(`rm -rf ${dir}`, err => err? console.error(err): ''); } }) .catch(err => { // catch the error from uploading jpg file to spaces console.error(err); uploadJpg2Space(courseId, chapterId, dir, files, index); }); }else if(category === 'room'){ roomSlide2SpacePromise(courseId, chapterId, dir, files[index]) .then((res) => { delete files[index]; if (Object.keys(files).length === 0) { console.log(bashmsg); let pages = bashmsg.slice(bashmsg.indexOf('Total pages: ')+13); let slides = generatorRoomMultipleArray(courseId,'slides', pages, 'jpg'); updateDBdata('room',{roomId:courseId,slideUrl:slides}) exec(`rm -rf ${dir}`, err => err? console.error(err): ''); } }) .catch(err => { // catch the error from uploading jpg file to spaces console.error(err); uploadJpg2Space(courseId, chapterId, dir, files, index); }); } } upload.post("/pdf", (req, res) => { uploadPdf2Server().single("pdf")(req, res, err => { if (err) { console.error(err); return res.status(401).send("upload pdf failed"); } const { courseId, chapterId ,roomId} = req.body; if(req.body.courseId && req.body.chapterId){ const raw = `${temp}/pdf/${chapterId}`; const slide = `${raw}/slides`; //Update status before run bash //to declare property is not empty updateStatus('chapter',courseId, chapterId, 'slideUrl','pending'); runBash(`./pdf2jpg.bash ${raw} ${chapterId}`) .then((res) => { readdir(slide, (err, files) => { if (err) return console.error(err); const filesTree = {}; files.forEach((file, i) => (filesTree[i] = file)); files.forEach((file, i) => { let bash = { message:res } uploadJpg2Space(courseId, chapterId, slide, filesTree, i, bash.message,'course'); }); }); }) .catch(err => console.error(err)); res.send("OK"); }else if (req.body.roomId) { const raw = `${temp}/pdf/${roomId}`; const slide = `${raw}/slides`; //Update status before run bash //to declare property is not empty updateStatus('room',null,null, 'slideUrl','pending',req.body.roomId); runBash(`./pdf2jpg.bash ${raw} ${roomId}`) .then((res) => { readdir(slide, (err, files) => { if (err) return console.error(err); const filesTree = {}; files.forEach((file, i) => (filesTree[i] = file)); files.forEach((file, i) => { let bash = { message:res } uploadJpg2Space(roomId, chapterId, slide, filesTree, i, bash.message,'room'); }); }); }) .catch(err => console.error(err)); res.send("OK"); }else{ res.status(422).send('INVALID PAYLOAD'); } }); }); const uploadClip2Server = () => multer({ storage: multer.diskStorage({ destination: (req, file, cb) => { const dir = `${temp}/raw-clips/`; mkdir(dir, { recursive: true }, () => cb(null, dir)); }, filename: (req, file, cb) => { const suffix = file.originalname.match(/\.[\w]+$/); cb(null, `${req.body.uuid}${suffix ? suffix[0] : ""}`); } }) }); const uploadClip2Space = (courseId, chapterId, dir, filename) => clip2SpacePromise(courseId, chapterId, dir, filename) .then((res) =>{ if(res.status === 200){ exec(`rm ${dir}/${filename}`,err => err? console.error(err): ''); queryLastIndex('chapter',chapterId,'clipUrl') .then((lastIndex)=>{ console.log(lastIndex); let clipUrl = generatorMultipleArray(courseId, chapterId, 'clips', lastIndex+1, 'mp4'); let thumbUrl = generatorMultipleArray(courseId, chapterId, 'thumbs', lastIndex+1, 'jpg'); updateDBdata('chapter',{chapterId:chapterId, clipUrl:clipUrl}) updateDBdata('chapter',{chapterId:chapterId, thumbUrl:thumbUrl}) }) .catch((err)=>{console.log(err)}); // updateDBdata('curriculum',{courseId:courseId,demo:res.url}) }else{ console.log('Upload clips Something Wrong.') } }) .catch(err => { // catch the error from uploading jpg file to spaces console.error(err); uploadClip2Space(courseId, chapterId, dir, filename); }); const uploadThumb2Space = (courseId, chapterId, dir, filename) => thumb2SpacePromise(courseId, chapterId, dir, filename) .then(() => exec(`rm ${dir}/${filename}`, err => err? console.error(err): '')) .catch(err => { // catch the error from uploading jpg file to spaces console.error(err); uploadThumb2Space(courseId, chapterId, dir, filename); }); upload.post("/clip", (req, res) => { uploadClip2Server().single("clip")(req, res, err => { if (err) { console.error(err); return res.status(401).send("upload clip failed"); } const { courseId, chapterId, uuid } = req.body; const { filename } = req.file; const raw = `${temp}/raw-clips/${filename}`; runBash(`./videoProcess.bash ${raw} ${temp}`) .then(() => { exec(`rm ${raw}`, err => err? console.error(err): ''); uploadClip2Space(courseId, chapterId, `${temp}/clips`, `${uuid}.mp4`); uploadThumb2Space(courseId, chapterId, `${temp}/thumbs`, `${uuid}.jpg`); }) .catch(err => console.error(err)) return res.send("upload clip successfully"); }); }); upload.post("/attach", (req, res) => { uploadAttachment2space().single("attachment")(req, res, err => { if (err) { console.error(err); return res.status(401).send("upload attachment failed"); }else{ let {courseId, chapterId } = req.body; const { originalname } = req.file; queryLatestData('chapter',chapterId,'attachmentUrl') .then((latestData) => { let baseUrl = `https://ccrb-cs.sgp1.digitaloceanspaces.com/course/${courseId}/attachments/${chapterId}/${originalname}` let attachmentUrl = latestData; attachmentUrl.push(baseUrl); updateDBdata('chapter',{courseId:courseId,chapterId:chapterId,attachmentUrl:attachmentUrl}) res.send("upload attachment successfully"); }) .catch(err=>{ console.log(err); }) } }); }); const uploadCover2Server = () => multer({ storage: multer.diskStorage({ destination: (req, file, cb) => { const dir = `${temp}/raw-covers`; mkdir(dir, { recursive: true }, () => cb(null, dir)); }, filename: (req, file, cb) => { const suffix = file.originalname.match(/\.[\w]+$/); cb(null, `${req.body.name}${suffix? suffix[0]: ''}`); } }) }); const uploadCover2Space = (courseId, dir, filename,chapterId) => cover2SpacePromise(courseId, '', dir, filename) .then((res) =>{ if(res.status === 200){ exec(`rm ${dir}/${filename}`,err => err? console.error(err): '') //Due to upload cover use same route path //verify chapterId is exist if(chapterId){ updateDBdata('chapter',{courseId:courseId,chapterId:chapterId,bg:res.url}) }else{ updateDBdata('curriculum',{courseId:courseId,poster:res.url}) } }else{ console.log('Something Wrong.') } }) .catch(err => { // catch the error from uploading jpg file to spaces console.error(err); uploadCover2Space(courseId, dir, filename); }); upload.post("/cover", (req, res) => { uploadCover2Server().single("cover")(req, res, err => { if (err) { console.error(err); return res.status(401).send("upload cover failed"); } const { courseId, name , chapterId } = req.body; const { filename } = req.file; const raw = `${temp}/raw-covers/${filename}`; const cover = `${temp}/covers` runBash(`./coverResize.bash ${raw} ${cover}/${name}`) .then(() => { exec(`rm ${raw}`, err => err? console.error(err): ''); uploadCover2Space(courseId, cover, `${name}.jpg`,chapterId||null); }) .catch(err => console.error(err)); return res.send("upload cover successfully"); }); }); const uploadDemo2Server = () => multer({ storage: multer.diskStorage({ destination: (req, file, cb) => { const dir = `${temp}/raw-demos`; mkdir(dir, { recursive: true }, () => cb(null, dir)); }, filename: (req, file, cb) => { const suffix = file.originalname.match(/\.[\w]+$/); cb(null, `${req.body.courseId}${suffix? suffix[0]: ''}`); } }) }); const uploadDemo2Space = (courseId, dir, filename) => demo2SpacePromise(courseId, '', dir, filename) .then((res) =>{ if(res.status === 200){ exec(`rm ${dir}/${filename}`,err => err? console.error(err): '') updateDBdata('curriculum',{courseId:courseId,demo:res.url}) }else{ console.log('Upload demo Something Wrong.') } }) .catch(err => { // catch the error from uploading jpg file to spaces console.error(err); uploadDemo2Space(courseId, dir, filename); }); upload.post("/demo", (req, res) => { uploadDemo2Server().single('demo')(req, res, err => { if (err) { console.error(err); return res.status(401).send("upload demo failed"); } const { courseId } = req.body; const { filename } = req.file; const raw = `${temp}/raw-demos/${filename}`; const type = req.file.mimetype.split('/')[0]; let bash = ''; if (type === 'image') { bash = './demoImageResize.bash'; } else if (type === 'video') { bash = './demoVideoResize.bash'; } else { return res.status(401).send("wrong file type"); } runBash(`${bash} ${raw} ${temp}/demos/${courseId}`) .then(() => { exec(`rm ${raw}`, err => err? console.error(err): ''); const suffix = type === 'image'? '.jpg': '.mp4'; uploadDemo2Space(courseId, `${temp}/demos`, `${courseId}${suffix}`); }) .catch(err => console.error(err)); return res.send("upload demo successfully"); }); }) // ---------------------------------------------------------------------------- // const photoDirPath = join(__dirname, "static", "images", "workshop", "3"); const imageStorage = multer.diskStorage({ destination: photoDirPath, filename: (req, file, cb) => { const { username } = req.body; const types = file.mimetype.split("/"); if (types[0] === "image") { cb( null, (username ? username : "Untitled") + `-${Date.now()}.${types[1]}` ); } } }); const singleImageStore = multer({ storage: imageStorage }).single("userphoto"); upload.get("/all_photos", (req, res) => { readdir(photoDirPath, (err, files) => { if (err) return res.json({ message: "error", error: err }); else return res.json({ message: "ok", files: files }); }); }); upload.post("/images", singleImageStore, (req, res) => { console.log("save photo"); res.json({ msg: "Upload photo successfully" }); }); module.exports = upload;