Skip to content

Commit 5f988ab

Browse files
committed
image upload feature
1 parent 1bd8719 commit 5f988ab

20 files changed

+136
-26
lines changed

client/build/asset-manifest.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"main.js": "static/js/main.4aeecb45.js",
3-
"main.js.map": "static/js/main.4aeecb45.js.map"
2+
"main.js": "static/js/main.506bb9b6.js",
3+
"main.js.map": "static/js/main.506bb9b6.js.map"
44
}

client/build/css/materialize.css

+2-2
Original file line numberDiff line numberDiff line change
@@ -6841,9 +6841,9 @@ textarea.materialize-textarea {
68416841
/* Remove default checkbox */
68426842
[type="checkbox"]:not(:checked),
68436843
[type="checkbox"]:checked {
6844-
position: absolute;
6844+
/* position: absolute;
68456845
opacity: 0;
6846-
pointer-events: none;
6846+
pointer-events: none; */
68476847
}
68486848

68496849
[type="checkbox"] {

client/build/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="theme-color" content="#000000"><link rel="manifest" href="/manifest.json"><link rel="shortcut icon" href="/favicon.ico"><link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,400italic,700"><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Patua+One:100,300,400,400italic,700"><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat:300,400,400italic,500,600,700,700italic,900"><link rel="stylesheet" href="/style.css"><link rel="stylesheet" href="/css/global.css"><link rel="stylesheet" href="/css/structure.css"><link rel="stylesheet" href="/css/blogfeed.css"><link rel="stylesheet" href="/css/custom.css"><link rel="stylesheet" href="/css/materialize.css"><title>BlogFeed</title></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script src="./js/jquery-2.1.4.min.js"></script><script src="./js/mfn.menu.js"></script><script src="./js/jquery.plugins.js"></script><script src="./js/jquery.jplayer.min.js"></script><script src="./js/animations/animations.js"></script><script src="./js/translate3d.js"></script><script src="./js/scripts.js"></script><script type="text/javascript" src="/static/js/main.4aeecb45.js"></script></body></html>
1+
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="theme-color" content="#000000"><link rel="manifest" href="/manifest.json"><link rel="shortcut icon" href="/favicon.ico"><link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,400italic,700"><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Patua+One:100,300,400,400italic,700"><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat:300,400,400italic,500,600,700,700italic,900"><link rel="stylesheet" href="/style.css"><link rel="stylesheet" href="/css/global.css"><link rel="stylesheet" href="/css/structure.css"><link rel="stylesheet" href="/css/blogfeed.css"><link rel="stylesheet" href="/css/custom.css"><link rel="stylesheet" href="/css/materialize.css"><title>BlogFeed</title></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script src="./js/jquery-2.1.4.min.js"></script><script src="./js/mfn.menu.js"></script><script src="./js/jquery.plugins.js"></script><script src="./js/jquery.jplayer.min.js"></script><script src="./js/animations/animations.js"></script><script src="./js/translate3d.js"></script><script src="./js/scripts.js"></script><script type="text/javascript" src="/static/js/main.506bb9b6.js"></script></body></html>

client/build/service-worker.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/build/static/js/main.4aeecb45.js

-2
This file was deleted.

client/build/static/js/main.4aeecb45.js.map

-1
This file was deleted.

client/build/static/js/main.506bb9b6.js

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/build/static/js/main.506bb9b6.js.map

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/public/css/materialize.css

+2-2
Original file line numberDiff line numberDiff line change
@@ -6841,9 +6841,9 @@ textarea.materialize-textarea {
68416841
/* Remove default checkbox */
68426842
[type="checkbox"]:not(:checked),
68436843
[type="checkbox"]:checked {
6844-
position: absolute;
6844+
/* position: absolute;
68456845
opacity: 0;
6846-
pointer-events: none;
6846+
pointer-events: none; */
68476847
}
68486848

68496849
[type="checkbox"] {

client/src/actions/index.js

+11-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,17 @@ export const handleToken = token => async dispatch => {
2525
dispatch({ type: FETCH_USER, payload: res.data });
2626
};
2727

28-
export const submitBlog = (values, history) => async dispatch => {
29-
const res = await axios.post('/api/blogs', values);
28+
export const submitBlog = (values, state, history) => async dispatch => {
29+
30+
const uploadImageRes = await axios.post("/api/uploadImage", {
31+
image: state.file,
32+
});
33+
34+
const res = await axios.post("/api/blogs", {
35+
...values,
36+
blogType: state.ispublic,
37+
imageUrl: uploadImageRes.data,
38+
});
3039

3140
history.push('/blogs');
3241
dispatch({ type: FETCH_BLOG, payload: res.data });

client/src/components/Landing.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class Landing extends Component {
3838
<div className="image_wrapper">
3939
<div className="mask" />
4040
<img
41-
src="images/blogger-blog-adventure2.jpg"
41+
src={`${blog.imageUrl}`}
4242
className="scale-with-grid wp-post-image"
4343
alt=""
4444
/>
@@ -63,7 +63,7 @@ class Landing extends Component {
6363
<ul className="post-categories">
6464
<li>
6565
<span>
66-
Adventures
66+
Public
6767
</span>
6868
</li>
6969
</ul>

client/src/components/blogs/BlogFormReview.js

+35-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,24 @@ import { withRouter } from 'react-router-dom';
77
import * as actions from '../../actions';
88

99
class BlogFormReview extends Component {
10-
state = { file: null };
10+
state = { file: null, ispublic : 'private' };
11+
12+
13+
convertBase64 = (file) => {
14+
return new Promise((resolve, reject) => {
15+
const fileReader = new FileReader();
16+
fileReader.readAsDataURL(file);
17+
18+
fileReader.onload = () => {
19+
resolve(fileReader.result);
20+
};
21+
22+
fileReader.onerror = (error) => {
23+
reject(error);
24+
};
25+
});
26+
};
27+
1128

1229
renderFields() {
1330
const { formValues } = this.props;
@@ -46,12 +63,21 @@ class BlogFormReview extends Component {
4663

4764
const { submitBlog, history, formValues } = this.props;
4865

49-
submitBlog(formValues, history);
66+
submitBlog(formValues, this.state, history);
67+
}
68+
69+
onFileChange = async (event) => {
70+
const base64 = await this.convertBase64(event.target.files[0]);
71+
this.setState({ file: base64 });
5072
}
5173

52-
onFileChange(event) {
53-
this.setState({ file: event.target.files });
54-
console.log(event.target.files);
74+
onSelection(event) {
75+
if(event.target.checked){
76+
this.setState({ ispublic: event.target.value });
77+
}
78+
else{
79+
this.setState({ ispublic: 'private' });
80+
}
5581
}
5682

5783
render() {
@@ -60,7 +86,10 @@ class BlogFormReview extends Component {
6086
<h5>Please confirm your entries</h5>
6187
{this.renderFields()}
6288
<h5>Add an Image</h5>
63-
<input onChange={this.onFileChange.bind(this)} type="file" accept="image/*" />
89+
<p>Resolution greater than or equal to 1000*600</p>
90+
<input onChange={this.onFileChange.bind(this)} className='input-field' type="file" accept="image/*" />
91+
<label>Check this to show on home page</label>
92+
<input onChange={this.onSelection.bind(this)} className='input-field' type="checkbox" id="isPublic" name="isPublic" value="public"></input>
6493
{this.renderButtons()}
6594
</form>
6695
);

client/src/components/blogs/BlogShow.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,25 @@ class BlogShow extends Component {
77
this.props.fetchBlog(this.props.match.params._id);
88
}
99

10+
renderImage() {
11+
if(this.props.blog.imageUrl) {
12+
return <img style={{ width: '100%' }} alt='blogImg' src={this.props.blog.imageUrl} />
13+
}
14+
}
15+
1016
render() {
1117
if (!this.props.blog) {
1218
return '';
1319
}
1420

15-
const { title, content } = this.props.blog;
21+
const { title, content, description } = this.props.blog;
1622

1723
return (
1824
<div className='m-2'>
1925
<h3>{title}</h3>
2026
<p>{content}</p>
27+
{this.renderImage()}
28+
<p>{description}</p>
2129
</div>
2230
);
2331
}
+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export default [
22
{ label: 'Blog Title', name: 'title' },
3-
{ label: 'Content', name: 'content' }
3+
{ label: 'Content', name: 'content' },
4+
{ label: 'Description', name: 'description' }
45
];

config/prod.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,8 @@ module.exports = {
33
googleClientSecret: process.env.GOOGLE_CLIENT_SECRET,
44
mongoURI: process.env.MONGO_URI,
55
redisURI: process.env.REDIS_URI,
6-
cookieKey: process.env.COOKIE_KEY
6+
cookieKey: process.env.COOKIE_KEY,
7+
cloud_name: process.env.CLOUD_NAME,
8+
api_key: process.env.API_KEY,
9+
api_secret: process.env.API_SECRET
710
};

index.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const cookieSession = require('cookie-session');
44
const passport = require('passport');
55
const bodyParser = require('body-parser');
66
const keys = require('./config/keys');
7+
const cors = require('cors');
78

89
require('./models/User');
910
require('./models/Blog');
@@ -18,7 +19,13 @@ mongoose.connect(keys.mongoURI, {
1819

1920
const app = express();
2021

21-
app.use(bodyParser.json());
22+
app.use(cors());
23+
24+
app.use(bodyParser.json({ limit: "25mb" }));
25+
app.use(bodyParser.urlencoded({
26+
extended: true,
27+
limit: "25mb"
28+
}));
2229
app.use(
2330
cookieSession({
2431
maxAge: 30 * 24 * 60 * 60 * 1000,
@@ -28,8 +35,14 @@ app.use(
2835
app.use(passport.initialize());
2936
app.use(passport.session());
3037

38+
app.use((req,res,next) => {
39+
res.setHeader("Access-Control-Allow-Origin", "*");
40+
next();
41+
})
42+
3143
require('./routes/authRoutes')(app);
3244
require('./routes/blogRoutes')(app);
45+
require('./routes/uploadRoutes')(app);
3346

3447
if (['production','ci'].includes(process.env.NODE_ENV)) {
3548
app.use(express.static('client/build'));

models/Blog.js

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ const { Schema } = mongoose;
55
const blogSchema = new Schema({
66
title: String,
77
content: String,
8+
description: String,
9+
imageUrl: String,
810
createdAt: { type: Date, default: Date.now },
911
blogType: {
1012
type: String,

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121
"dependencies": {
2222
"aws-sdk": "2.188.0",
2323
"body-parser": "1.17.2",
24+
"cloudinary": "^1.36.4",
2425
"concurrently": "3.5.0",
2526
"cookie-session": "2.0.0-beta.2",
27+
"cors": "^2.8.5",
2628
"express": "4.15.3",
2729
"jest": "23.6.0",
2830
"migrate-mongoose": "3.2.2",

routes/blogRoutes.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,14 @@ module.exports = app => {
3939
});
4040

4141
app.post('/api/blogs', requireLogin, cleanCache, async (req, res) => {
42-
const { title, content } = req.body;
42+
const { title, content, description, blogType, imageUrl } = req.body;
4343

4444
const blog = new Blog({
4545
title,
4646
content,
47+
description,
48+
blogType,
49+
imageUrl,
4750
_user: req.user.id
4851
});
4952

routes/uploadRoutes.js

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
const keys = require('../config/keys');
2+
const requireLogin = require('../middlewares/requireLogin');
3+
var cloudinary = require("cloudinary").v2;
4+
5+
6+
cloudinary.config({
7+
cloud_name: keys.cloud_name,
8+
api_key: keys.api_key,
9+
api_secret: keys.api_secret,
10+
});
11+
12+
const opts = {
13+
overwrite: true,
14+
invalidate: true,
15+
resource_type: "auto",
16+
folder: "blogfeed"
17+
};
18+
19+
const uploadImage = (image) => {
20+
//imgage = > base64
21+
return new Promise((resolve, reject) => {
22+
cloudinary.uploader.upload(image, opts, (error, result) => {
23+
if (result && result.secure_url) {
24+
console.log(result.secure_url);
25+
return resolve(result.secure_url);
26+
}
27+
console.log(error.message);
28+
return reject({ message: error.message });
29+
});
30+
});
31+
};
32+
33+
34+
module.exports = (app) => {
35+
app.post("/api/uploadImage", requireLogin, (req, res) => {
36+
uploadImage(req.body.image)
37+
.then((url) => res.send(url))
38+
.catch((err) => res.status(500).send(err));
39+
});
40+
};

0 commit comments

Comments
 (0)