node.jsmongodbexpresshandlebars.jsimgur

TypeError: Cannot read property 'then' of undefined , TypeError: _cb is not a function


my code in github, but I didn't upload the latest version: https://github.com/godzillalogan/markdownblog

I use node.js and express.js framework. Database use mongoDB. I am using the package Imgur and dotenv, try to upload image to imgur.

But I encounter some bug:

bug:

App is running on http://localhost:3000
mongodb connected!
TypeError: Cannot read property 'then' of undefined
    at Promise (D:\Github\markdownblog\helpers\file-helpers.js:26:7)
    at new Promise (<anonymous>)
    at imgurFileHandler (D:\Github\markdownblog\helpers\file-helpers.js:23:10)
    at router.put (D:\Github\markdownblog\routes\modules\admin.js:115:26)
    at process._tickCallback (internal/process/next_tick.js:68:7)
D:\Github\markdownblog\node_modules\imgur-node-api\lib\imgur.js:34
        _cb(null, body);
        ^

TypeError: _cb is not a function
    at Request._callback (D:\Github\markdownblog\node_modules\imgur-node-api\lib\imgur.js:34:9)
    at Request.self.callback (D:\Github\markdownblog\node_modules\request\index.js:142:22)
    at Request.emit (events.js:182:13)
    at Request.<anonymous> (D:\Github\markdownblog\node_modules\request\index.js:856:14)
    at Request.emit (events.js:187:15)
    at IncomingMessage.<anonymous> (D:\Github\markdownblog\node_modules\request\index.js:808:12)
    at IncomingMessage.emit (events.js:187:15)
    at endReadableNT (_stream_readable.js:1094:12)
    at process._tickCallback (internal/process/next_tick.js:63:19)
[nodemon] app crashed - waiting for file changes before starting...

Here is my code:

app.js:

const path = require('path') // 引入 path 套件
const express = require('express')
const session = require('express-session')

const bodyParser = require('body-parser')  //新版express以內建body-parser
const { engine } = require('express-handlebars');
const flash = require('connect-flash')
if (process.env.NODE_ENV !== 'production') {  //要放在const routes = require('./routes')前面
  require('dotenv').config()
}

const routes = require('./routes')

const app = express()
const PORT = process.env.PORT || 3000
const methodOverride = require('method-override')  // 載入 method-override
//others code............

helpers/file-helpers.js:

const fs = require('fs') // 引入 fs 模組, fs 模組是 Node.js 提供專門來處理檔案的原生模組


//載入 imgur 套件
const imgur = require('imgur-node-api')

const IMGUR_CLIENT_ID = process.env.IMGUR_CLIENT_ID
console.log('IMGUR_CLIENT_ID:',IMGUR_CLIENT_ID)
imgur.setClientID(IMGUR_CLIENT_ID)

const localFileHandler =  file => { // file 是 multer 處理完的檔案
  return new Promise((resolve, reject) => {
    if (!file) return resolve(null) 
    const fileName = `upload/${file.originalname}`
    return fs.promises.readFile(file.path)
      .then(data => fs.promises.writeFile(fileName, data))
      .then(() => resolve(`/${fileName}`))
      .catch(err => reject(err))
  })
}

const imgurFileHandler = file => {
  return new Promise((resolve, reject) => {
    if (!file) return resolve(null)
    return imgur.upload(file.path)
      .then(img => {
        // resolve(img?.link || null) // 檢查 img 是否存在
        resolve(img ? img.link : null)
      })
      .catch(err => reject(err))
  })
}
module.exports = {
  localFileHandler,
  imgurFileHandler  //img
}

routes/modules/admin:

const express = require('express')
const router = express.Router()
const Article = require('../../models/article');
const Category = require('../../models/category');
const User = require('../../models/user');
const Contact = require('../../models/contact');
const upload = require('../../middleware/multer') // 載入 multer
const { imgurFileHandler } = require('../../helpers/file-helpers') // 將 file-helper 載進來

////others code....

//edit user
router.put('/users/:id', upload.single('avatar'), async (req, res)=>{
  try{
  console.log('有到edit user嗎')
  const _id = req.params.id
  const { name,avatar,introduction } = req.body
  const { file } = req // 把檔案取出來
 
  const user = await User.findOne({ _id})
  const filePath = await imgurFileHandler(file) // 把檔案傳到 file-helper 處理 
  
  user.name = name
  // user.cover = filePath || user.cover
  user.avatar = filePath || user.avatar
  user.introduction = introduction
  await user.save()
  res.redirect('/about')
  }catch(e){
    console.log(e)
    res.redirect(`/admin/users`)
  }
  // const {title,description,markdown} = req.body   //和new一樣才能將markdown轉成html
  //   Article.create({...req.body})
  //   res.redirect('/')


////others code....
})


What I have try:

I think it is about promise problem, and localFileHandler in helpers/file-helpers.js is work successful , but why imgurFileHandler in helpers/file-helpers.js is not work .

Thank you for your help.


Solution

  • I move it from helpers/file-helpers.js to routes/modules/admin.js. And the way is success. But I think there would have another better way.

    routes/modules/admin.js

    I add Imgur to the route in create article,edit article and edit user.

    routes/modules/admin.js

    //Create
    router.post('/articles', upload.single('image'), async (req,res)=>{
      // console.log(req.body)
      // const article = new Article({
      //     title: req.body.title,
      //     description: req.body.description,
      //     markdown: req.body.markdown
      // });
      try{
        const {title,category,description,markdown} = req.body
        const{file} = req
    
        console.log('file:',file)
        if (file){
          imgur.setClientID(IMGUR_CLIENT_ID)
          imgur.upload(file.path,(err, img) =>{
            Article.create({...req.body, image: file ? img.data.link: null})
          })
        }else{
          Article.create({...req.body})
        }
       
        
        res.redirect('/admin/articles')
      } catch(e){
        console.log(e)
        res.render('admin/articles',{ article })
      }
    })
    
    ////Update
    //到edit頁
    router.get('/articles/edit/:id', async (req, res) => {
      // const _id = req.params.id
      // return Article.findOne({ _id})
      //   .lean()
      //   .then((article) => res.render('edit', { article}))
      //   .catch(error => console.log(error))
      try{
      const _id = req.params.id
      const article =  await Article.findOne({ _id}).lean()
      const categories = await Category.find().lean().sort({createdAt:'desc'})
      res.render('edit', { article,categories})
      }catch{
        console.log(e)
        res.redirect(`/articles/edit/:id`)
      }
    })
    
    //edit article
    router.put('/articles/:id', upload.single('image'), async (req, res)=>{
    
      try{
        const _id = req.params.id
        const { title,description,markdown,category } = req.body
        const { file } = req // 把檔案取出來
        const article = await Article.findOne({ _id})
        if (file){
            // const filePath = await imgurFileHandler(file) // 把檔案傳到 file-helper 處理 
            imgur.setClientID(IMGUR_CLIENT_ID)
            imgur.upload(file.path,async (err, img) =>{
            // Article.update({...req.body, image: file ? img.data.link: article.image})
            article.title = title
            article.description = description
            article.markdown = markdown
            article.category = category
            article.image = img.data.link
            await article.save()
            })
        }else{
          article.title = title
          article.description = description
          article.markdown = markdown
          article.category = category
          await article.save()
        }
        res.redirect('/admin/articles')
      }catch(e){
        console.log(e)
        res.redirect(`/admin/articles`)
      }
      // const {title,description,markdown} = req.body   //和new一樣才能將markdown轉成html
      //   Article.create({...req.body})
      //   res.redirect('/')
    })