upload.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. const multer = require("multer");
  2. const upload = require("express").Router();
  3. const { exec } = require("child_process");
  4. const { mkdir, readdir, readFile } = require("fs");
  5. const { homedir } = require("os");
  6. const { join } = require("path");
  7. const aws = require("aws-sdk");
  8. const multerS3 = require("multer-s3");
  9. const config = require('./config');
  10. const axios = require('axios');
  11. const spacesEndpoint = new aws.Endpoint("sgp1.digitaloceanspaces.com");
  12. const s3 = new aws.S3({ endpoint: spacesEndpoint });
  13. const temp = `${homedir()}/temp`;
  14. const updateStatus = (urlType,courseId=null, chapterId=null, property,status,roomId=null) =>{
  15. axios({
  16. method:'put',
  17. url:`${config.server}/${urlType}/upload`,
  18. data:{
  19. courseId:courseId,
  20. chapterId:chapterId,
  21. [property]:status,
  22. roomId:roomId
  23. },
  24. headers:{
  25. 'Authorization':'yezicoco'
  26. }
  27. })
  28. .then((res) => {
  29. console.log(res.data)
  30. })
  31. .catch((err) => {
  32. console.log(err)
  33. })
  34. }
  35. const updateDBdata = (urlType,payload) => {
  36. //params
  37. //urlType: chapter or curriculum
  38. axios({
  39. method:'put',
  40. url:`${config.server}/${urlType}/upload`,
  41. data:payload,
  42. headers:{
  43. 'Authorization':'yezicoco'
  44. }
  45. })
  46. .then((res)=>{
  47. console.log(res.data)
  48. })
  49. .catch((err)=>{
  50. console.log(err)
  51. })
  52. }
  53. const queryLastIndex = (urlType, chapterId,property) =>
  54. new Promise(function(resolve, reject){
  55. axios({
  56. method:'get',
  57. url:`${config.server}/${urlType}/pre/id/${chapterId}`,
  58. headers:{
  59. 'Authorization':'yezicoco'
  60. }
  61. })
  62. .then((res)=>{
  63. resolve(res.data[property].length)
  64. })
  65. .catch((err)=>{
  66. console.log(err)
  67. })
  68. })
  69. const queryLatestData = (urlType, chapterId, property) =>
  70. new Promise ((resolve, reject) => {
  71. axios({
  72. method:'get',
  73. url:`${config.server}/${urlType}/pre/id/${chapterId}`,
  74. headers:{
  75. 'Authorization':'yezicoco'
  76. }
  77. })
  78. .then((res)=>{
  79. resolve(res.data[property])
  80. })
  81. .catch((err)=>{
  82. console.log(err)
  83. })
  84. })
  85. const generatorMultipleArray = (courseId, chapterId, type,length,format='',filename='') =>{
  86. let arr = [];
  87. let baseUrl = `https://ccrb-cs.sgp1.digitaloceanspaces.com/course/${courseId}/${type}/${chapterId}/${chapterId}_`
  88. for(let index = 1 ; index <= length;index++){
  89. arr.push(baseUrl+index+'.'+format + filename);
  90. }
  91. return arr;
  92. };
  93. const generatorRoomMultipleArray = (roomId, type,length,format='',filename='') =>{
  94. let arr = [];
  95. let baseUrl = `https://ccrb-cs.sgp1.digitaloceanspaces.com/room/${roomId}/${type}/${roomId}_`
  96. for(let index = 1 ; index <= length;index++){
  97. arr.push(baseUrl+index+'.'+format + filename);
  98. }
  99. return arr;
  100. };
  101. const uploadAttachment2space = () => multer({
  102. storage: multerS3({
  103. s3: s3,
  104. bucket: (req, file, cb) => {
  105. cb(null, `ccrb-cs/course/${req.body.courseId}/attachments/${req.body.chapterId}`);
  106. },
  107. acl: "public-read",
  108. key: function(req, file, cb) {
  109. cb(null,file.originalname);
  110. }
  111. })
  112. });
  113. const uploadFile2Space = (type,category) =>{
  114. if(category === 'course'){
  115. return (course, bucket='', dir, file) => new Promise((resovle, reject) => {
  116. const params = {
  117. Bucket: `ccrb-cs/course/${course}/${type}${bucket?'/':''}${bucket}`,
  118. Key: `${file}`,
  119. ACL: "public-read"
  120. };
  121. readFile(`${dir}/${file}`, (err, buf) => {
  122. if (err)
  123. return console.error(err);
  124. params.Body = buf;
  125. s3.putObject(params, (err,data) => {
  126. if (err) {
  127. console.error(err);
  128. return reject(err);
  129. }else{
  130. let response = {
  131. status:200,
  132. url:`${config.space}/course/${course}/${type}${bucket?'/':''}${bucket}/${file}`,
  133. }
  134. return resovle(response);
  135. }
  136. });
  137. });
  138. })
  139. }else if(category === 'room'){
  140. return (roomId, bucket='', dir, file) => new Promise((resovle, reject) => {
  141. const params = {
  142. Bucket: `ccrb-cs/room/${roomId}/${type}${bucket?'/':''}${bucket}`,
  143. Key: `${file}`,
  144. ACL: "public-read"
  145. };
  146. readFile(`${dir}/${file}`, (err, buf) => {
  147. if (err)
  148. return console.error(err);
  149. params.Body = buf;
  150. s3.putObject(params, (err,data) => {
  151. if (err) {
  152. console.error(err);
  153. return reject(err);
  154. }else{
  155. let response = {
  156. status:200,
  157. url:`${config.space}/room/${roomId}/${type}${bucket?'/':''}${bucket}/${file}`,
  158. }
  159. return resovle(response);
  160. }
  161. });
  162. });
  163. })
  164. }
  165. };
  166. //course
  167. const slide2SpacePromise = uploadFile2Space('slides','course');
  168. const clip2SpacePromise = uploadFile2Space('clips','course');
  169. const thumb2SpacePromise = uploadFile2Space('thumbs','course');
  170. const cover2SpacePromise = uploadFile2Space('covers','course');
  171. const demo2SpacePromise = uploadFile2Space('demos','course');
  172. //pdf
  173. const roomSlide2SpacePromise = uploadFile2Space('slides','room');
  174. const uploadPdf2Server = () => multer({
  175. storage: multer.diskStorage({
  176. destination: (req, file, cb) => {
  177. const filename = req.body.roomId? req.body.roomId:req.body.chapterId;
  178. const dir = `${temp}/pdf/${filename}`;
  179. mkdir(dir, { recursive: true }, () => cb(null, dir));
  180. },
  181. filename: (req, file, cb) => {
  182. const filename = req.body.roomId? req.body.roomId:req.body.chapterId;
  183. return cb(null, `${filename}.pdf`)
  184. }
  185. })
  186. });
  187. const runBash = command => new Promise((resovle, reject) => {
  188. exec(command, (err,stdout, stderr) => err? reject(err): resovle(stdout));
  189. });
  190. const uploadJpg2Space = (courseId, chapterId, dir, files, index,bashmsg,category) =>
  191. {if(category === 'course'){
  192. slide2SpacePromise(courseId, chapterId, dir, files[index])
  193. .then((res) => {
  194. delete files[index];
  195. if (Object.keys(files).length === 0) {
  196. console.log(bashmsg);
  197. let pages = bashmsg.slice(bashmsg.indexOf('Total pages: ')+13);
  198. let slides = generatorMultipleArray(courseId, chapterId, 'slides', pages, 'jpg');
  199. updateDBdata('chapter',{courseId:courseId,chapterId:chapterId,slideUrl:slides})
  200. exec(`rm -rf ${dir}`, err => err? console.error(err): '');
  201. }
  202. })
  203. .catch(err => {
  204. // catch the error from uploading jpg file to spaces
  205. console.error(err);
  206. uploadJpg2Space(courseId, chapterId, dir, files, index);
  207. });
  208. }else if(category === 'room'){
  209. roomSlide2SpacePromise(courseId, chapterId, dir, files[index])
  210. .then((res) => {
  211. delete files[index];
  212. if (Object.keys(files).length === 0) {
  213. console.log(bashmsg);
  214. let pages = bashmsg.slice(bashmsg.indexOf('Total pages: ')+13);
  215. let slides = generatorRoomMultipleArray(courseId,'slides', pages, 'jpg');
  216. updateDBdata('room',{roomId:courseId,slideUrl:slides})
  217. exec(`rm -rf ${dir}`, err => err? console.error(err): '');
  218. }
  219. })
  220. .catch(err => {
  221. // catch the error from uploading jpg file to spaces
  222. console.error(err);
  223. uploadJpg2Space(courseId, chapterId, dir, files, index);
  224. });
  225. }
  226. }
  227. upload.post("/pdf", (req, res) => {
  228. uploadPdf2Server().single("pdf")(req, res, err => {
  229. if (err) {
  230. console.error(err);
  231. return res.status(401).send("upload pdf failed");
  232. }
  233. const { courseId, chapterId ,roomId} = req.body;
  234. if(req.body.courseId && req.body.chapterId){
  235. const raw = `${temp}/pdf/${chapterId}`;
  236. const slide = `${raw}/slides`;
  237. //Update status before run bash
  238. //to declare property is not empty
  239. updateStatus('chapter',courseId, chapterId, 'slideUrl','pending');
  240. runBash(`./pdf2jpg.bash ${raw} ${chapterId}`)
  241. .then((res) => {
  242. readdir(slide, (err, files) => {
  243. if (err)
  244. return console.error(err);
  245. const filesTree = {};
  246. files.forEach((file, i) => (filesTree[i] = file));
  247. files.forEach((file, i) => {
  248. let bash = {
  249. message:res
  250. }
  251. uploadJpg2Space(courseId, chapterId, slide, filesTree, i, bash.message,'course');
  252. });
  253. });
  254. })
  255. .catch(err => console.error(err));
  256. res.send("OK");
  257. }else if (req.body.roomId) {
  258. const raw = `${temp}/pdf/${roomId}`;
  259. const slide = `${raw}/slides`;
  260. //Update status before run bash
  261. //to declare property is not empty
  262. updateStatus('room',null,null, 'slideUrl','pending',req.body.roomId);
  263. runBash(`./pdf2jpg.bash ${raw} ${roomId}`)
  264. .then((res) => {
  265. readdir(slide, (err, files) => {
  266. if (err)
  267. return console.error(err);
  268. const filesTree = {};
  269. files.forEach((file, i) => (filesTree[i] = file));
  270. files.forEach((file, i) => {
  271. let bash = {
  272. message:res
  273. }
  274. uploadJpg2Space(roomId, chapterId, slide, filesTree, i, bash.message,'room');
  275. });
  276. });
  277. })
  278. .catch(err => console.error(err));
  279. res.send("OK");
  280. }else{
  281. res.status(422).send('INVALID PAYLOAD');
  282. }
  283. });
  284. });
  285. const uploadClip2Server = () => multer({
  286. storage: multer.diskStorage({
  287. destination: (req, file, cb) => {
  288. const dir = `${temp}/raw-clips/`;
  289. mkdir(dir, { recursive: true }, () => cb(null, dir));
  290. },
  291. filename: (req, file, cb) => {
  292. const suffix = file.originalname.match(/\.[\w]+$/);
  293. cb(null, `${req.body.uuid}${suffix ? suffix[0] : ""}`);
  294. }
  295. })
  296. });
  297. const uploadClip2Space = (courseId, chapterId, dir, filename) =>
  298. clip2SpacePromise(courseId, chapterId, dir, filename)
  299. .then((res) =>{
  300. if(res.status === 200){
  301. exec(`rm ${dir}/${filename}`,err => err? console.error(err): '');
  302. queryLastIndex('chapter',chapterId,'clipUrl')
  303. .then((lastIndex)=>{
  304. console.log(lastIndex);
  305. let clipUrl = generatorMultipleArray(courseId, chapterId, 'clips', lastIndex+1, 'mp4');
  306. let thumbUrl = generatorMultipleArray(courseId, chapterId, 'thumbs', lastIndex+1, 'jpg');
  307. updateDBdata('chapter',{chapterId:chapterId, clipUrl:clipUrl})
  308. updateDBdata('chapter',{chapterId:chapterId, thumbUrl:thumbUrl})
  309. })
  310. .catch((err)=>{console.log(err)});
  311. // updateDBdata('curriculum',{courseId:courseId,demo:res.url})
  312. }else{
  313. console.log('Upload clips Something Wrong.')
  314. }
  315. })
  316. .catch(err => {
  317. // catch the error from uploading jpg file to spaces
  318. console.error(err);
  319. uploadClip2Space(courseId, chapterId, dir, filename);
  320. });
  321. const uploadThumb2Space = (courseId, chapterId, dir, filename) =>
  322. thumb2SpacePromise(courseId, chapterId, dir, filename)
  323. .then(() => exec(`rm ${dir}/${filename}`,
  324. err => err? console.error(err): ''))
  325. .catch(err => {
  326. // catch the error from uploading jpg file to spaces
  327. console.error(err);
  328. uploadThumb2Space(courseId, chapterId, dir, filename);
  329. });
  330. upload.post("/clip", (req, res) => {
  331. uploadClip2Server().single("clip")(req, res, err => {
  332. if (err) {
  333. console.error(err);
  334. return res.status(401).send("upload clip failed");
  335. }
  336. const { courseId, chapterId, uuid } = req.body;
  337. const { filename } = req.file;
  338. const raw = `${temp}/raw-clips/${filename}`;
  339. runBash(`./videoProcess.bash ${raw} ${temp}`)
  340. .then(() => {
  341. exec(`rm ${raw}`, err => err? console.error(err): '');
  342. uploadClip2Space(courseId, chapterId, `${temp}/clips`, `${uuid}.mp4`);
  343. uploadThumb2Space(courseId, chapterId, `${temp}/thumbs`, `${uuid}.jpg`);
  344. })
  345. .catch(err => console.error(err))
  346. return res.send("upload clip successfully");
  347. });
  348. });
  349. upload.post("/attach", (req, res) => {
  350. uploadAttachment2space().single("attachment")(req, res, err => {
  351. if (err) {
  352. console.error(err);
  353. return res.status(401).send("upload attachment failed");
  354. }else{
  355. let {courseId, chapterId } = req.body;
  356. const { originalname } = req.file;
  357. queryLatestData('chapter',chapterId,'attachmentUrl')
  358. .then((latestData) => {
  359. let baseUrl = `https://ccrb-cs.sgp1.digitaloceanspaces.com/course/${courseId}/attachments/${chapterId}/${originalname}`
  360. let attachmentUrl = latestData;
  361. attachmentUrl.push(baseUrl);
  362. updateDBdata('chapter',{courseId:courseId,chapterId:chapterId,attachmentUrl:attachmentUrl})
  363. res.send("upload attachment successfully");
  364. })
  365. .catch(err=>{
  366. console.log(err);
  367. })
  368. }
  369. });
  370. });
  371. const uploadCover2Server = () => multer({
  372. storage: multer.diskStorage({
  373. destination: (req, file, cb) => {
  374. const dir = `${temp}/raw-covers`;
  375. mkdir(dir, { recursive: true }, () => cb(null, dir));
  376. },
  377. filename: (req, file, cb) => {
  378. const suffix = file.originalname.match(/\.[\w]+$/);
  379. cb(null, `${req.body.name}${suffix? suffix[0]: ''}`);
  380. }
  381. })
  382. });
  383. const uploadCover2Space = (courseId, dir, filename,chapterId) =>
  384. cover2SpacePromise(courseId, '', dir, filename)
  385. .then((res) =>{
  386. if(res.status === 200){
  387. exec(`rm ${dir}/${filename}`,err => err? console.error(err): '')
  388. //Due to upload cover use same route path
  389. //verify chapterId is exist
  390. if(chapterId){
  391. updateDBdata('chapter',{courseId:courseId,chapterId:chapterId,bg:res.url})
  392. }else{
  393. updateDBdata('curriculum',{courseId:courseId,poster:res.url})
  394. }
  395. }else{
  396. console.log('Something Wrong.')
  397. }
  398. })
  399. .catch(err => {
  400. // catch the error from uploading jpg file to spaces
  401. console.error(err);
  402. uploadCover2Space(courseId, dir, filename);
  403. });
  404. upload.post("/cover", (req, res) => {
  405. uploadCover2Server().single("cover")(req, res, err => {
  406. if (err) {
  407. console.error(err);
  408. return res.status(401).send("upload cover failed");
  409. }
  410. const { courseId, name , chapterId } = req.body;
  411. const { filename } = req.file;
  412. const raw = `${temp}/raw-covers/${filename}`;
  413. const cover = `${temp}/covers`
  414. runBash(`./coverResize.bash ${raw} ${cover}/${name}`)
  415. .then(() => {
  416. exec(`rm ${raw}`, err => err? console.error(err): '');
  417. uploadCover2Space(courseId, cover, `${name}.jpg`,chapterId||null);
  418. })
  419. .catch(err => console.error(err));
  420. return res.send("upload cover successfully");
  421. });
  422. });
  423. const uploadDemo2Server = () => multer({
  424. storage: multer.diskStorage({
  425. destination: (req, file, cb) => {
  426. const dir = `${temp}/raw-demos`;
  427. mkdir(dir, { recursive: true }, () => cb(null, dir));
  428. },
  429. filename: (req, file, cb) => {
  430. const suffix = file.originalname.match(/\.[\w]+$/);
  431. cb(null, `${req.body.courseId}${suffix? suffix[0]: ''}`);
  432. }
  433. })
  434. });
  435. const uploadDemo2Space = (courseId, dir, filename) =>
  436. demo2SpacePromise(courseId, '', dir, filename)
  437. .then((res) =>{
  438. if(res.status === 200){
  439. exec(`rm ${dir}/${filename}`,err => err? console.error(err): '')
  440. updateDBdata('curriculum',{courseId:courseId,demo:res.url})
  441. }else{
  442. console.log('Upload demo Something Wrong.')
  443. }
  444. })
  445. .catch(err => {
  446. // catch the error from uploading jpg file to spaces
  447. console.error(err);
  448. uploadDemo2Space(courseId, dir, filename);
  449. });
  450. upload.post("/demo", (req, res) => {
  451. uploadDemo2Server().single('demo')(req, res, err => {
  452. if (err) {
  453. console.error(err);
  454. return res.status(401).send("upload demo failed");
  455. }
  456. const { courseId } = req.body;
  457. const { filename } = req.file;
  458. const raw = `${temp}/raw-demos/${filename}`;
  459. const type = req.file.mimetype.split('/')[0];
  460. let bash = '';
  461. if (type === 'image') {
  462. bash = './demoImageResize.bash';
  463. } else if (type === 'video') {
  464. bash = './demoVideoResize.bash';
  465. } else {
  466. return res.status(401).send("wrong file type");
  467. }
  468. runBash(`${bash} ${raw} ${temp}/demos/${courseId}`)
  469. .then(() => {
  470. exec(`rm ${raw}`, err => err? console.error(err): '');
  471. const suffix = type === 'image'? '.jpg': '.mp4';
  472. uploadDemo2Space(courseId, `${temp}/demos`, `${courseId}${suffix}`);
  473. })
  474. .catch(err => console.error(err));
  475. return res.send("upload demo successfully");
  476. });
  477. })
  478. // ---------------------------------------------------------------------------- //
  479. const photoDirPath = join(__dirname, "static", "images", "workshop", "3");
  480. const imageStorage = multer.diskStorage({
  481. destination: photoDirPath,
  482. filename: (req, file, cb) => {
  483. const { username } = req.body;
  484. const types = file.mimetype.split("/");
  485. if (types[0] === "image") {
  486. cb(
  487. null,
  488. (username ? username : "Untitled") + `-${Date.now()}.${types[1]}`
  489. );
  490. }
  491. }
  492. });
  493. const singleImageStore = multer({ storage: imageStorage }).single("userphoto");
  494. upload.get("/all_photos", (req, res) => {
  495. readdir(photoDirPath, (err, files) => {
  496. if (err) return res.json({ message: "error", error: err });
  497. else return res.json({ message: "ok", files: files });
  498. });
  499. });
  500. upload.post("/images", singleImageStore, (req, res) => {
  501. console.log("save photo");
  502. res.json({ msg: "Upload photo successfully" });
  503. });
  504. module.exports = upload;