<template>
<LeftSideBar></LeftSideBar>
<div class="create-post">
<h2>Create a New Post</h2>
<!-- Form for post data -->
<form @submit.prevent="submitPost">
<!-- Post Title -->
<div>
<label for="title">Title</label>
<input
type="text"
id="title"
v-model="postData.title"
placeholder="Enter post title"
required
/>
</div>
<!-- Post Caption (Thumbnail) -->
<div>
<label for="caption">Thumbnail Caption</label>
<input
type="text"
id="caption"
v-model="postData.thumbnailCaption"
placeholder="Enter thumbnail caption"
/>
</div>
<!-- Blocks -->
<div v-for="(block, index) in postData.blocks" :key="index" class="block-section">
<label>Block {{ index + 1 }}</label>
<div v-if="block.type === 'text'">
<textarea
v-model="block.content"
@input="autoResize"
placeholder="Enter text content"
></textarea>
</div>
<div v-if="block.type === 'image'">
<input
type="file"
@change="handleImageUpload($event, index)"
accept="image/*"
name="content"
/>
<img v-if="block.previewUrl" :src="block.previewUrl" alt="Image Preview" class="preview-image" />
</div>
</div>
<!-- Add Block Buttons -->
<button type="button" @click="addTextBlock">Add Text Block</button>
<button type="button" @click="addImageBlock">Add Image Block</button>
<!-- Submit and Save Draft Buttons -->
<button type="submit">Create Post</button>
<button type="button" @click="saveDraft">Save Draft</button>
</form>
<!-- Modal for confirming post creation -->
<div v-if="showModal" class="modal">
<div class="modal-content">
<p>Are you sure you want to submit this post?</p>
<button @click="submitPost">Yes, Submit</button>
<button @click="showModal = false">Cancel</button>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios';
import LeftSideBar from '@/components/LeftSideBar.vue';
import { mapState } from 'vuex';
export default {
name: 'CreatePost',
components: {
LeftSideBar,
},
computed: {
...mapState('account', {
isLoggedIn: state => state.status.loggedIn,
userId: state => state.user ? state.user.id : null
})
},
data() {
return {
postData: {
title: '',
caption: '',
group_id: null,
thumbnailCaption: '',
blocks: []
},
fontSize: 16,
currentBlock: { type: '', content: '' },
showModal: false
};
},
mounted() {
if (!this.isLoggedIn) {
alert('Please log in to create a post.');
this.$router.push('/login');
}
},
methods: {
async submitPost() {
this.showModal = false;
try {
// Create the main post first
const postResponse = await axios.post('http://localhost:5000/post/create-post', {
group_id: this.postData.group_id,
user_id: sessionStorage.getItem('user_id'),
title: this.postData.title,
caption: this.postData.thumbnailCaption
});
const postId = postResponse.data.post_id;
// Upload each block
// Upload each block
for (let [index, block] of this.postData.blocks.entries()) {
// Prepare form data for image blocks
const formData = new FormData();
formData.append('post_id', postId); // The ID of the post
formData.append('type', block.type); // 'text' or 'image'
formData.append('order', index + 1); // Order of the block
if (block.type === 'image') {
// Append the image file for upload to S3
formData.append('content', block.file); // File to upload
} else {
// For text blocks, directly append content
formData.append('content', block.content); // Content for text
}
// Send request to create the block
await axios.post('http://localhost:5000/post/create-post-block', formData, {
headers: {
'Content-Type': 'multipart/form-data' // Ensure correct content type for file upload
}
});
}
alert("Post created successfully");
this.$router.push('/');
} catch (error) {
console.error("Failed to create post:", error);
alert("An error occurred while creating the post.");
}
},
handleImageUpload(event, index) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
this.$set(this.postData.blocks[index], 'previewUrl', e.target.result);
};
this.$set(this.postData.blocks[index], 'file', file); // Store the file for later upload
reader.readAsDataURL(file);
}
},
addTextBlock() {
this.postData.blocks.push({ type: 'text', content: '' });
},
addImageBlock() {
this.postData.blocks.push({ type: 'image', content: '', previewUrl: '', file: null });
}
}
};
</script>
This is the code for my post create page in a blog-like socila network which create one block at a time to integrate post and text between each other. I am having a problem, the system works normal if a block is text but if it is an image, it does not put the url of the file in s3 into the database
THis is my api
exports.createPostBlock = async (req, res) => {
const { post_id, type, order } = req.body;
try {
// Ensure required fields are present
if (!post_id || !order) {
return res.status(400).json({ error: 'post_id and order are required fields' });
}
let content = null;
// If type is 'image', handle the file upload
if (type === 'image' && req.file) {
content = req.file.location; // The file URL returned from S3 or local storage
} else if (type === 'text') {
content = req.body.content; // Assuming content is passed for text posts
}
// Create PostBlock in the database
const postBlock = await Post_block.create({
post_id,
type,
content,
order,
});
res.status(201).json({ message: 'Post block created successfully', postBlock });
} catch (error) {
console.error('Error creating post block:', error);
res.status(500).json({ error: 'Error creating post block', details: error.message });
}
};
This is my middleware and route
const multer = require('multer');
const multerS3 = require('multer-s3');
const AWS = require('aws-sdk');
const {S3Client} = require("@aws-sdk/client-s3");
require('dotenv').config();
// Initialize AWS S3
const s3 = new S3Client({
region: 'ap-southeast-1',
credentials: {
accessKeyId: '*hidden',
secretAccessKey: '*hidden'
},
});
// Set up multer storage configuration using S3
const storage = multerS3({
s3: s3,
bucket: '*hiddden', // Ensure the AWS S3 bucket name is in your .env file
key: (req, file, cb) => {
cb(null, `uploads/${Date.now()}-${file.originalname}`);
}
});
// Set up multer with the storage configuration
const image_upload = multer({ storage: storage });
// Export the upload middleware to be used in routes
module.exports = image_upload;
router.post('/create-post-block', postController.createPostBlock,upload.single('content'))
The APIs is successfully tested using postman
I tried everything, attaching the file directly to the api, uploading the image first…