-
Social Media 만들기 - 11)createPost 작성하기NODE.JS 2021. 7. 11. 00:45
post와 comment 모델을 만들어주자.
const mongoose = require('mongoose') const postSchema = new mongoose.Schema({ content:String, images:{ type:Array, required:true }, likes:{ type:mongoose.Types.ObjectId, ref:'User' }, comments:{ type:mongoose.Types.ObjectId, ref:'comment' }, user:{ type:mongoose.Types.ObjectId, ref:'user' } },{timestamps:true}) const Post = mongoose.model('Post', postSchema) module.exports = {Post}
const mongoose = require('mongoose') const commentSchema = new mongoose.Schema({ content:{ type:String, required:true }, tag:Object, reply:mongoose.Types.ObjectId, likes:[{ type:mongoose.Types.ObjectId, ref:'User' }], user:{ type:mongoose.Types.ObjectId, ref:'User' }, postId:mongoose.Types.ObjectId, postUserId:mongoose.Types.ObjectId },{timestamps:true}) const Comment = mongoose.model('Comment', commentSchema) module.exports = {Comment}
submit 버튼을 클릭하면 사진과 데이터를 보내도록 설정해주자.
statusModal.js
import React, { useRef, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { createPost } from '../_actions/postActions' import { ALERT, STATUS } from '../_constants/globalConstants' import Alert from './Alert' function StatusModal() { const userLogin = useSelector(state => state.userLogin) const {userInfo} = userLogin const theme = useSelector(state => state.theme) const [content, setcontent] = useState('') const dispatch = useDispatch() const [Images, setImages] = useState([]) const [stream, setStream] = useState(false) const [tracks, setTracks] = useState('') const videoRef = useRef() const canvasRef = useRef() const handleChangeImages=(e)=>{ const files = [...e.target.files] let newImages= [] let err = '' files.forEach(file=>{ if(!file) return err = "File doesn't exist." if(file.type !== 'image/jpeg' && file.type !=='image/png'){ return err = "Image format is incorrect." } return newImages.push(file) }) if(err) dispatch({type:ALERT, payload:{error:err}}) setImages([...Images, ...newImages]) } const deleteImage=(index)=>{ const newArr = [...Images] newArr.splice(index, 1) setImages(newArr) } const handleStream= () =>{ setStream(true) // navigator.getWebcam = (navigator.getUserMedia || navigator.webKitGetUserMedia || navigator.moxGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia); if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia){ navigator.mediaDevices.getUserMedia({video:true}) .then(mediastream=>{ videoRef.current.srcObject = mediastream videoRef.current.play() const track = mediastream.getTracks() setTracks(track[0]) }).catch(err=>console.log(err)) } // else{ // navigator.getWebcam({video:true}, // function(stream){ // videoRef.current.srcObject = stream // videoRef.current.play() // const track = stream.getTracks() // setTracks(track[0]) // }, function(){ // console.log("Web cam is not accesible.") // }) // } } const handleCapture= () =>{ const width = videoRef.current.clientWidth; const height = videoRef.current.clientHeight; canvasRef.current.setAttribute("width", width) canvasRef.current.setAttribute("height", height) const ctx = canvasRef.current.getContext('2d') ctx.drawImage(videoRef.current, 0, 0, width, height) let URL = canvasRef.current.toDataURL() setImages([...Images, URL]) } const handleStopStream= () =>{ tracks.stop() setStream(false) } const handleSubmit= (e) =>{ e.preventDefault() if(Images.length===0){ dispatch({type:ALERT, payload:{error:"Please add your photo."}}) } dispatch(createPost({content, Images})) setcontent('') setImages([]) if(tracks) tracks.stop() dispatch({type:STATUS, payload:false}) } return ( <div className="status_modal"> <form onSubmit={handleSubmit}> <div className="status_header"> <h5 className="m-0">Create Post</h5> <span onClick={()=>dispatch({type:STATUS, payload:false})}>×</span> </div> <div className="status_body"> <textarea name="content" value = {content} placeholder={`${userInfo.user.username}, what are you thinking?`} onChange={(e)=>setcontent(e.target.value)} /> <div className="show_images"> { Images && Images.map((image, index)=>( <div key={index} id="file_img"> <img src={image.camera? image.camera : URL.createObjectURL(image)} alt="images" className="img-thumbnail rounded" style={{filter:theme? 'invert(1)':'inver(0)'}} /> <span onClick={()=>deleteImage(index)}>×</span> </div> )) } </div> { stream && <div className="stream position-relative"> <video autoPlay muted style={{filter:theme? 'invert(1)':'inver(0)'}} ref={videoRef} width='100%' height='100%'></video> <span onClick={handleStopStream}>×</span> <canvas ref={canvasRef} style={{display:'none'}}></canvas> </div> } <div className="input_images"> { stream ? <i className="fas fa-camera" onClick={handleCapture}></i> : <> <i className="fas fa-camera" onClick={handleStream}></i> <div className="file_upload"> <i className="fas fa-image"></i> <input type="file" name="file" id="file_up" multiple accept="image/*" onChange={handleChangeImages}/> </div> </> } </div> </div> <div className="statue_footer"> <button className="btn btn-secondary w-100" type="submit" type="submit">Post</button> </div> </form> </div> ) } export default StatusModal
사진을 보내면 postuploads폴더에 사진이 저장되도록 router설정해주자.
Router>postUploadRouter.js
const multer = require('multer') const express = require('express'); const { auth } = require('../middleware/auth'); const postUploadRouter = express.Router(); const storage = multer.diskStorage({ destination(req,file,cb){ cb(null, 'postuploads/') }, filename(req,file,cb){ cb(null, `${Date.now()}.jpg`); } }) const postupload = multer({storage}) postUploadRouter.post('/',auth, postupload.single('image'), (req,res)=>{ res.send(`/${req.file.path}`) }) module.exports = postUploadRouter
최상위에 postuploads/폴더를 만들어주고 안에 file.txt를 만들어준다.
server.js에 이미지 저장 경로를 설정해주자.
const __variableOfChoice = path.resolve(); app.use('/profileuploads', express.static(path.join(__variableOfChoice, '/profileuploads'))) app.use('/postuploads', express.static(path.join(__variableOfChoice, '/postuploads'))) app.use('/api/postuploads', require('./routes/postUploadRouter'));
이제 postcreate하는 라우터를 만들어주자.
postRouter.js
const express = require('express') const {Post} = require('../models/Post') const {auth} = require('../middleware/auth') const postRouter = express.Router() postRouter.post('/', auth, async(req, res)=>{ // console.log(req.body) try{ const newPost = new Post({'content':req.body.content, 'images':req.body.images,'user':req.body.userId}) await newPost.save() res.send({newPost}) }catch(err){ return res.status(500).json({message:err.message}) } }) module.exports = postRouter
Constant를 만들어주자.
postConstants.js
export const CREATE_POST_REQUEST = 'CREATE_POST_REQUEST' export const CREATE_POST_SUCCESS = 'CREATE_POST_SUCCESS' export const CREATE_POST_FAIL = 'CREATE_POST_FAIL' export const CREATE_POST_RESET = 'CREATE_POST_RESET'
postActions.js
여기서 각이미지마다 form데이터를 돌아가면서 설정하고 저장하고,
이미지를 폴더에 저장하는 라우트를 보내준다.
import axios from "axios" import { CREATE_POST_FAIL, CREATE_POST_REQUEST, CREATE_POST_SUCCESS } from "../_constants/postConstants" export const createPost = ({content, Images})=> async(dispatch, getState)=>{ const {userLogin:{userInfo}} = getState() dispatch({ type:CREATE_POST_REQUEST, payload:{loading:true} }) try{ let imgArr = []; if(Images.length>0){ for(const item of Images){ const bodyFormData = new FormData() if(item.camera){ bodyFormData.append("image", item.camera) }else{ bodyFormData.append("image", item) } const data = await axios.post('/api/postuploads', bodyFormData,{ headers:{'Content-Type' : 'multipart/form-data', authorization:`Bearer ${userInfo.token}`} }) imgArr.push(data) } } const res = await axios.post('/api/post', {content, images:imgArr, userId:userInfo.user._id,user:userInfo.user},{ headers:{authorization:`Bearer ${userInfo.token}`} }) dispatch({ type:CREATE_POST_SUCCESS, payload:res.data.newPost }) }catch(error){ dispatch({ type:CREATE_POST_FAIL, payload: error.response && error.response.data.message ? error.response.data.message : error.message }) } }
받아온 newpost 데이터를 스테잇에 저장해준다. (reducer 통해서)
postReducers.js
import { CREATE_POST_FAIL, CREATE_POST_REQUEST, CREATE_POST_RESET, CREATE_POST_SUCCESS } from "../_constants/postConstants"; export const postCreateReducer = (state={}, action)=>{ switch(action.type){ case CREATE_POST_REQUEST: return {loading:true, success:false} case CREATE_POST_SUCCESS: return {loading:false, newpost:action.payload, success:true} case CREATE_POST_FAIL: return {loading:false, error:action.payload,success:false} case CREATE_POST_RESET: return {} default: return state } }
store.js
createpost:postCreateReducer,
잘생성된다.
'NODE.JS' 카테고리의 다른 글
Social Media 만들기 - 12) get posts 가져오기 (0) 2021.07.12 req.body 가 undefined으로 뜰 때 (2) 2021.07.11 Social Media 만들기 - 10)Status, create post 창 만들기 (0) 2021.07.10 Social Media 만들기 - 9) following, followers 보여주기 (0) 2021.07.10 Cast to ObjectId failed for value "" at path "_id" 오류 (0) 2021.07.10