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.
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.
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('/')
})