reorganized routes, store memos in db
This commit is contained in:
		
							parent
							
								
									7e3b2606f9
								
							
						
					
					
						commit
						17858006f6
					
				@ -1,6 +1,7 @@
 | 
			
		||||
SESSION_SECRET=
 | 
			
		||||
MONGODB_CONN="mongodb://127.0.0.1:27017/howfeed"
 | 
			
		||||
SALT_WORK_FACTOR=10
 | 
			
		||||
API_TOKEN=token123
 | 
			
		||||
 | 
			
		||||
SMTP_SERVER=
 | 
			
		||||
SMTP_PORT=587
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								src/models/memo.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/models/memo.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
import mongoose from 'mongoose';
 | 
			
		||||
 | 
			
		||||
const { Schema } = mongoose;
 | 
			
		||||
const MemoSchema = new Schema({
 | 
			
		||||
    message: { type: String, required: true },
 | 
			
		||||
    author: {
 | 
			
		||||
        type: mongoose.Schema.Types.ObjectId,
 | 
			
		||||
        ref: 'User'
 | 
			
		||||
    },
 | 
			
		||||
    time: { type: Date, default: Date.now }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default mongoose.model('Memo', MemoSchema);
 | 
			
		||||
							
								
								
									
										12
									
								
								src/routes/a/random.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/routes/a/random.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
import Article from '../../models/article.js';
 | 
			
		||||
 | 
			
		||||
export async function get(req, res, next)
 | 
			
		||||
{
 | 
			
		||||
	var articleCount = await Article.countDocuments();
 | 
			
		||||
	var random = Math.floor(Math.random() * articleCount);
 | 
			
		||||
	var randomArticle = await Article.findOne().skip(random).select('slug');
 | 
			
		||||
	res.writeHead(200, {
 | 
			
		||||
		'Content-Type': 'application/json'
 | 
			
		||||
	});
 | 
			
		||||
	res.end(JSON.stringify(randomArticle));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								src/routes/api/meet.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/routes/api/meet.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
			
		||||
import NodeCache from 'node-cache';
 | 
			
		||||
const cache = new NodeCache();
 | 
			
		||||
 | 
			
		||||
export async function get(req, res, next)
 | 
			
		||||
{
 | 
			
		||||
	if (req.query.token === process.env.API_TOKEN) {
 | 
			
		||||
		const time = cache.get('lastMeetingTime');
 | 
			
		||||
		res.writeHead(200, {
 | 
			
		||||
			'Content-Type': 'application/json'
 | 
			
		||||
		});
 | 
			
		||||
		res.end(JSON.stringify({
 | 
			
		||||
			LastMeetingTime: time ? time.toJSON() : undefined
 | 
			
		||||
		}));
 | 
			
		||||
	} else {
 | 
			
		||||
		next();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function post(req, res, next)
 | 
			
		||||
{
 | 
			
		||||
	if (req.body.token === process.env.API_TOKEN) {
 | 
			
		||||
		const time = new Date();
 | 
			
		||||
		const success = cache.set('lastMeetingTime', time, 3600);
 | 
			
		||||
		if (success) {
 | 
			
		||||
			res.writeHead(200, {
 | 
			
		||||
				'Content-Type': 'application/json'
 | 
			
		||||
			});
 | 
			
		||||
			res.end(JSON.stringify({
 | 
			
		||||
				LastMeetingTime: time.toJSON()
 | 
			
		||||
			}));
 | 
			
		||||
		} else {
 | 
			
		||||
			res.writeHead(500, {
 | 
			
		||||
				'Content-Type': 'application/json'
 | 
			
		||||
			});
 | 
			
		||||
			res.end(JSON.stringify({
 | 
			
		||||
				Error: 'Failed to store meeting time in cache!'
 | 
			
		||||
			}));
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		next();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										84
									
								
								src/routes/api/memo.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								src/routes/api/memo.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,84 @@
 | 
			
		||||
import Memo from '../../models/memo.js';
 | 
			
		||||
 | 
			
		||||
export async function get(req, res, next)
 | 
			
		||||
{
 | 
			
		||||
	if (req.query.token === process.env.API_TOKEN) {
 | 
			
		||||
		try {
 | 
			
		||||
			const memos = await Memo.find();
 | 
			
		||||
			res.writeHead(200, {
 | 
			
		||||
				'Content-Type': 'application/json'
 | 
			
		||||
			});
 | 
			
		||||
			res.end(JSON.stringify(memos));
 | 
			
		||||
		} catch (err) {
 | 
			
		||||
			res.writeHead(500, {
 | 
			
		||||
				'Content-Type': 'application/json'
 | 
			
		||||
			});
 | 
			
		||||
			res.end(JSON.stringify({
 | 
			
		||||
				Error: 'Failed to retrieve memos from database!'
 | 
			
		||||
			}));
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		next();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function post(req, res, next)
 | 
			
		||||
{
 | 
			
		||||
	if (req.body.token === process.env.API_TOKEN) {
 | 
			
		||||
		const msg = req.body.message;
 | 
			
		||||
		if (!msg) {
 | 
			
		||||
			res.writeHead(400, {
 | 
			
		||||
				'Content-Type': 'application/json'
 | 
			
		||||
			});
 | 
			
		||||
			res.end(JSON.stringify({
 | 
			
		||||
				Error: 'You must provide a memo message'
 | 
			
		||||
			}));
 | 
			
		||||
		}
 | 
			
		||||
		try {
 | 
			
		||||
			const memo = await new Memo({
 | 
			
		||||
				message: msg,
 | 
			
		||||
				author: req.user && req.user._id
 | 
			
		||||
			});
 | 
			
		||||
			await memo.save();
 | 
			
		||||
			const memos = await Memo.find();
 | 
			
		||||
			res.writeHead(200, {
 | 
			
		||||
				'Content-Type': 'application/json'
 | 
			
		||||
			});
 | 
			
		||||
			res.end(JSON.stringify(memos));
 | 
			
		||||
		} catch (err) {
 | 
			
		||||
			res.writeHead(500, {
 | 
			
		||||
				'Content-Type': 'application/json'
 | 
			
		||||
			});
 | 
			
		||||
			res.end(JSON.stringify({
 | 
			
		||||
				Error: 'Failed to store memo in database!'
 | 
			
		||||
			}));
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		next();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function del(req, res, next)
 | 
			
		||||
{
 | 
			
		||||
	if (req.body.token === process.env.API_TOKEN) {
 | 
			
		||||
		const { id } = req.params;
 | 
			
		||||
		const memo = await Memo.findOneAndDelete(id);
 | 
			
		||||
 | 
			
		||||
		if (memo) {
 | 
			
		||||
			const memos = await Memo.find();
 | 
			
		||||
				res.writeHead(200, {
 | 
			
		||||
					'Content-Type': 'application/json'
 | 
			
		||||
				});
 | 
			
		||||
				res.end(JSON.stringify(memos));
 | 
			
		||||
		} else {
 | 
			
		||||
			res.writeHead(404, {
 | 
			
		||||
				'Content-Type': 'application/json'
 | 
			
		||||
			});
 | 
			
		||||
			res.end(JSON.stringify({
 | 
			
		||||
				message: `Not found`
 | 
			
		||||
			}));
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		next();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								src/routes/cms/logout.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/routes/cms/logout.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
export async function get(req, res)
 | 
			
		||||
{
 | 
			
		||||
	req.logout();
 | 
			
		||||
	req.session.destroy(function (err) {
 | 
			
		||||
		if (err) next(err);
 | 
			
		||||
		return res.redirect('/');
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +1,68 @@
 | 
			
		||||
import crypto from 'crypto';
 | 
			
		||||
import fs from 'fs';
 | 
			
		||||
import User from '../../models/user.js';
 | 
			
		||||
 | 
			
		||||
export async function post(req, res, next)
 | 
			
		||||
{
 | 
			
		||||
	if (!req.user) {
 | 
			
		||||
		res.writeHead(401, {
 | 
			
		||||
			'Content-Type': 'application/json'
 | 
			
		||||
		});
 | 
			
		||||
		res.end(JSON.stringify({
 | 
			
		||||
			message: `You must be logged in to set an avatar.`
 | 
			
		||||
		}));
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	try {
 | 
			
		||||
		const { upload } = req.files;
 | 
			
		||||
		if (!upload) {
 | 
			
		||||
			res.writeHead(422, {
 | 
			
		||||
				'Content-Type': 'application/json'
 | 
			
		||||
			});
 | 
			
		||||
			res.end(JSON.stringify({
 | 
			
		||||
				message: `You must supply a file.`
 | 
			
		||||
			}));
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		if (!/^image\//.test(upload.mimetype)) {
 | 
			
		||||
			res.writeHead(422, {
 | 
			
		||||
				'Content-Type': 'application/json'
 | 
			
		||||
			});
 | 
			
		||||
			res.end(JSON.stringify({
 | 
			
		||||
				message: `Invalid MIME type for the uploaded image.`
 | 
			
		||||
			}));
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		if (upload.truncated) {
 | 
			
		||||
			res.writeHead(422, {
 | 
			
		||||
				'Content-Type': 'application/json'
 | 
			
		||||
			});
 | 
			
		||||
			res.end(JSON.stringify({
 | 
			
		||||
				message: `Received truncated image file. Try again with a smaller file.`
 | 
			
		||||
			}));
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		const ext = upload.name.match(/(\.[^.]+)$/)[0];
 | 
			
		||||
		const filename = crypto.randomBytes(20).toString('hex') + ext;
 | 
			
		||||
		const url = `/u/${filename}`;
 | 
			
		||||
		await upload.mv('./static' + url);
 | 
			
		||||
		const user = await User.findById(req.user._id);
 | 
			
		||||
		req.user.avatar = user.avatar = filename;
 | 
			
		||||
		await user.save();
 | 
			
		||||
		res.writeHead(200, {
 | 
			
		||||
			'Content-Type': 'application/json'
 | 
			
		||||
		});
 | 
			
		||||
		res.end(JSON.stringify({ filename }));
 | 
			
		||||
	} catch (err) {
 | 
			
		||||
		res.writeHead(500, {
 | 
			
		||||
			'Content-Type': 'application/json'
 | 
			
		||||
		});
 | 
			
		||||
		res.end(JSON.stringify({
 | 
			
		||||
			message: `Failed to upload image: ${err}`
 | 
			
		||||
		}));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function del(req, res)
 | 
			
		||||
{
 | 
			
		||||
	if (!req.user) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										41
									
								
								src/routes/rss.xml.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/routes/rss.xml.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
import RSS from 'rss';
 | 
			
		||||
import Article from '../models/article.js';
 | 
			
		||||
 | 
			
		||||
export async function get(req, res)
 | 
			
		||||
{
 | 
			
		||||
	let year = new Date().getFullYear();
 | 
			
		||||
	let feed = new RSS({
 | 
			
		||||
		title: 'HowFeed.biz Articles',
 | 
			
		||||
		feed_url: 'http://howfeed.biz/rss.xml',
 | 
			
		||||
		site_url: 'http://howfeed.biz/',
 | 
			
		||||
		image_url: 'http://howfeed.biz/logo.png',
 | 
			
		||||
		language: 'en',
 | 
			
		||||
		webMaster: 'webmaster@howfeed.biz',
 | 
			
		||||
		copyright: `${year} FemboyFinancial Holdings Co., Ltd. (USA LLC)`
 | 
			
		||||
	});
 | 
			
		||||
	let articles = await Article.find().populate({
 | 
			
		||||
		path: 'author',
 | 
			
		||||
		select: 'realname avatar'
 | 
			
		||||
	}).populate({
 | 
			
		||||
		path: 'category'
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	for (let article of articles) {
 | 
			
		||||
		feed.item({
 | 
			
		||||
			title: article.title,
 | 
			
		||||
			description: article.html,
 | 
			
		||||
			url: `http://howfeed.biz/a/${article.slug}`,
 | 
			
		||||
			categories: [ article.category.name ],
 | 
			
		||||
			author: article.author.realname,
 | 
			
		||||
			date: article.created_at,
 | 
			
		||||
			enclosure: {
 | 
			
		||||
				url: `http://howfeed.biz/a/${article.image}`
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res.writeHead(200, {
 | 
			
		||||
		'Content-Type': 'application/rss+xml'
 | 
			
		||||
	});
 | 
			
		||||
	res.end(feed.xml());
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								src/routes/suggestions.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/routes/suggestions.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,52 @@
 | 
			
		||||
require('dotenv').config();
 | 
			
		||||
import nodemailer from 'nodemailer';
 | 
			
		||||
 | 
			
		||||
const { SMTP_USERNAME, SMTP_PASSWORD, SMTP_SERVER, SMTP_PORT, SMTP_RECIPIENTS } = process.env;
 | 
			
		||||
const mailer = nodemailer.createTransport({
 | 
			
		||||
    host: SMTP_SERVER,
 | 
			
		||||
    port: 587,
 | 
			
		||||
    secure: SMTP_PORT === 465,
 | 
			
		||||
    auth: {
 | 
			
		||||
        user: SMTP_USERNAME,
 | 
			
		||||
        pass: SMTP_PASSWORD
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export async function post(req, res)
 | 
			
		||||
{
 | 
			
		||||
	let { name, title, message } = req.body;
 | 
			
		||||
	if (!message) {
 | 
			
		||||
		res.writeHead(422, {
 | 
			
		||||
			'Content-Type': 'application/json'
 | 
			
		||||
		});
 | 
			
		||||
		res.end(JSON.stringify({
 | 
			
		||||
			message: 'No message supplied'
 | 
			
		||||
		}));
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	name = name || 'Anonymous';
 | 
			
		||||
	title = title || 'Suggestion';
 | 
			
		||||
	try {
 | 
			
		||||
		await mailer.sendMail({
 | 
			
		||||
			from: `"HowFeed Suggestions" <${SMTP_USERNAME}>`,
 | 
			
		||||
			to: SMTP_RECIPIENTS,
 | 
			
		||||
			subject: title,
 | 
			
		||||
			text: `Suggested by ${name}:
 | 
			
		||||
 | 
			
		||||
			${message}`
 | 
			
		||||
		});
 | 
			
		||||
		res.writeHead(200, {
 | 
			
		||||
			'Content-Type': 'application/json'
 | 
			
		||||
		});
 | 
			
		||||
		res.end(JSON.stringify({
 | 
			
		||||
			message: 'Your suggestion was delivered.'
 | 
			
		||||
		}));
 | 
			
		||||
	} catch (err) {
 | 
			
		||||
		res.writeHead(500, {
 | 
			
		||||
			'Content-Type': 'application/json'
 | 
			
		||||
		});
 | 
			
		||||
		res.end(JSON.stringify({
 | 
			
		||||
			message: err.message
 | 
			
		||||
		}));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										255
									
								
								src/server.js
									
									
									
									
									
								
							
							
						
						
									
										255
									
								
								src/server.js
									
									
									
									
									
								
							@ -1,3 +1,4 @@
 | 
			
		||||
require('dotenv').config();
 | 
			
		||||
import express from 'express';
 | 
			
		||||
import session from 'express-session';
 | 
			
		||||
import compression from 'compression';
 | 
			
		||||
@ -9,27 +10,21 @@ import { Strategy } from 'passport-local';
 | 
			
		||||
import sessionFileStore from 'session-file-store';
 | 
			
		||||
import { RateLimiterMemory } from 'rate-limiter-flexible';
 | 
			
		||||
import fileUpload from 'express-fileupload';
 | 
			
		||||
import nodemailer from 'nodemailer';
 | 
			
		||||
import fs from 'fs';
 | 
			
		||||
import cors from 'cors';
 | 
			
		||||
import helmet from 'helmet';
 | 
			
		||||
import useragent from 'useragent';
 | 
			
		||||
import RSS from 'rss';
 | 
			
		||||
import path from 'path';
 | 
			
		||||
import crypto from 'crypto';
 | 
			
		||||
import NodeCache from 'node-cache';
 | 
			
		||||
import Article from './models/article.js';
 | 
			
		||||
import Category from './models/category.js';
 | 
			
		||||
import User from './models/user.js';
 | 
			
		||||
import legacyMiddleware from './legacy/middleware.js';
 | 
			
		||||
import legacyRouter from './legacy/router.js';
 | 
			
		||||
 | 
			
		||||
require('dotenv').config();
 | 
			
		||||
const FileStore = sessionFileStore(session);
 | 
			
		||||
const cache = new NodeCache();
 | 
			
		||||
 | 
			
		||||
const { PORT, NODE_ENV, SESSION_SECRET, MONGODB_CONN,
 | 
			
		||||
        SMTP_USERNAME, SMTP_PASSWORD, SMTP_SERVER, SMTP_PORT, SMTP_RECIPIENTS } = process.env;
 | 
			
		||||
const { PORT, NODE_ENV, SESSION_SECRET, MONGODB_CONN } = process.env;
 | 
			
		||||
const dev = NODE_ENV === 'development';
 | 
			
		||||
 | 
			
		||||
mongoose.set('useNewUrlParser', true);
 | 
			
		||||
@ -115,16 +110,6 @@ const isAuthor = function(req, res, next) {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const mailer = nodemailer.createTransport({
 | 
			
		||||
    host: SMTP_SERVER,
 | 
			
		||||
    port: 587,
 | 
			
		||||
    secure: SMTP_PORT === 465,
 | 
			
		||||
    auth: {
 | 
			
		||||
        user: SMTP_USERNAME,
 | 
			
		||||
        pass: SMTP_PASSWORD
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
var app = express();
 | 
			
		||||
app.set('view engine', 'ejs');
 | 
			
		||||
@ -149,13 +134,6 @@ mainRouter
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
    .get('/cms/logout', (req, res, next) => {
 | 
			
		||||
        req.logout();
 | 
			
		||||
        req.session.destroy(function (err) {
 | 
			
		||||
            if (err) next(err);
 | 
			
		||||
            return res.redirect('/');
 | 
			
		||||
        });
 | 
			
		||||
    })
 | 
			
		||||
    .post('/cms/article/:edit?',
 | 
			
		||||
        isAuthor,
 | 
			
		||||
        async function(req, res, next) {
 | 
			
		||||
@ -334,234 +312,7 @@ mainRouter
 | 
			
		||||
                }));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
	.get('/a/random',
 | 
			
		||||
		async function(req, res, next) {
 | 
			
		||||
			var articleCount = await Article.countDocuments();
 | 
			
		||||
			var random = Math.floor(Math.random() * articleCount);
 | 
			
		||||
			var randomArticle = await Article.findOne().skip(random).select('slug');
 | 
			
		||||
			res.writeHead(200, {
 | 
			
		||||
				'Content-Type': 'application/json'
 | 
			
		||||
			});
 | 
			
		||||
			res.end(JSON.stringify(randomArticle));
 | 
			
		||||
		}
 | 
			
		||||
	)
 | 
			
		||||
    .post('/me/avatar',
 | 
			
		||||
        async function(req, res, next) {
 | 
			
		||||
            if (!req.user) {
 | 
			
		||||
                res.writeHead(401, {
 | 
			
		||||
                    'Content-Type': 'application/json'
 | 
			
		||||
                });
 | 
			
		||||
                res.end(JSON.stringify({
 | 
			
		||||
                    message: `You must be logged in to set an avatar.`
 | 
			
		||||
                }));
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            try {
 | 
			
		||||
                const { upload } = req.files;
 | 
			
		||||
                if (!upload) {
 | 
			
		||||
                    res.writeHead(422, {
 | 
			
		||||
                        'Content-Type': 'application/json'
 | 
			
		||||
                    });
 | 
			
		||||
                    res.end(JSON.stringify({
 | 
			
		||||
                        message: `You must supply a file.`
 | 
			
		||||
                    }));
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                if (!/^image\//.test(upload.mimetype)) {
 | 
			
		||||
                    res.writeHead(422, {
 | 
			
		||||
                        'Content-Type': 'application/json'
 | 
			
		||||
                    });
 | 
			
		||||
                    res.end(JSON.stringify({
 | 
			
		||||
                        message: `Invalid MIME type for the uploaded image.`
 | 
			
		||||
                    }));
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                if (upload.truncated) {
 | 
			
		||||
                    res.writeHead(422, {
 | 
			
		||||
                        'Content-Type': 'application/json'
 | 
			
		||||
                    });
 | 
			
		||||
                    res.end(JSON.stringify({
 | 
			
		||||
                        message: `Received truncated image file. Try again with a smaller file.`
 | 
			
		||||
                    }));
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                const ext = upload.name.match(/(\.[^.]+)$/)[0];
 | 
			
		||||
                const filename = crypto.randomBytes(20).toString('hex') + ext;
 | 
			
		||||
                const url = `/u/${filename}`;
 | 
			
		||||
                await upload.mv('./static' + url);
 | 
			
		||||
                const user = await User.findById(req.user._id);
 | 
			
		||||
                req.user.avatar = user.avatar = filename;
 | 
			
		||||
                await user.save();
 | 
			
		||||
                res.writeHead(200, {
 | 
			
		||||
                    'Content-Type': 'application/json'
 | 
			
		||||
                });
 | 
			
		||||
                res.end(JSON.stringify({ filename }));
 | 
			
		||||
            } catch (err) {
 | 
			
		||||
                res.writeHead(500, {
 | 
			
		||||
                    'Content-Type': 'application/json'
 | 
			
		||||
                });
 | 
			
		||||
                res.end(JSON.stringify({
 | 
			
		||||
                    message: `Failed to upload image: ${err}`
 | 
			
		||||
                }));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
	.get('/rss.xml', async function (req, res) {
 | 
			
		||||
		let year = new Date().getFullYear();
 | 
			
		||||
		let feed = new RSS({
 | 
			
		||||
			title: 'HowFeed.biz Articles',
 | 
			
		||||
			feed_url: 'http://howfeed.biz/rss.xml',
 | 
			
		||||
			site_url: 'http://howfeed.biz/',
 | 
			
		||||
			image_url: 'http://howfeed.biz/logo.png',
 | 
			
		||||
			language: 'en',
 | 
			
		||||
			webMaster: 'webmaster@howfeed.biz',
 | 
			
		||||
			copyright: `${year} FemboyFinancial Holdings Co., Ltd. (USA LLC)`
 | 
			
		||||
		});
 | 
			
		||||
		let articles = await Article.find().populate({
 | 
			
		||||
			path: 'author',
 | 
			
		||||
			select: 'realname avatar'
 | 
			
		||||
		}).populate({
 | 
			
		||||
			path: 'category'
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		for (let article of articles) {
 | 
			
		||||
			feed.item({
 | 
			
		||||
				title: article.title,
 | 
			
		||||
				description: article.html,
 | 
			
		||||
				url: `http://howfeed.biz/a/${article.slug}`,
 | 
			
		||||
				categories: [ article.category.name ],
 | 
			
		||||
				author: article.author.realname,
 | 
			
		||||
				date: article.created_at,
 | 
			
		||||
				enclosure: {
 | 
			
		||||
					url: `http://howfeed.biz/a/${article.image}`
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		res.writeHead(200, {
 | 
			
		||||
			'Content-Type': 'application/rss+xml'
 | 
			
		||||
		});
 | 
			
		||||
		res.end(feed.xml());
 | 
			
		||||
    })
 | 
			
		||||
    .post('/suggestions', async function (req, res) {
 | 
			
		||||
        let { name, title, message } = req.body;
 | 
			
		||||
        if (!message) {
 | 
			
		||||
            res.writeHead(422, {
 | 
			
		||||
                'Content-Type': 'application/json'
 | 
			
		||||
            });
 | 
			
		||||
            res.end(JSON.stringify({
 | 
			
		||||
                message: 'No message supplied'
 | 
			
		||||
            }));
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        name = name || 'Anonymous';
 | 
			
		||||
        title = title || 'Suggestion';
 | 
			
		||||
        try {
 | 
			
		||||
            await mailer.sendMail({
 | 
			
		||||
                from: `"HowFeed Suggestions" <${SMTP_USERNAME}>`,
 | 
			
		||||
                to: SMTP_RECIPIENTS,
 | 
			
		||||
                subject: title,
 | 
			
		||||
                text: `Suggested by ${name}:
 | 
			
		||||
 | 
			
		||||
                ${message}`
 | 
			
		||||
            });
 | 
			
		||||
            res.writeHead(200, {
 | 
			
		||||
                'Content-Type': 'application/json'
 | 
			
		||||
            });
 | 
			
		||||
            res.end(JSON.stringify({
 | 
			
		||||
                message: 'Your suggestion was delivered.'
 | 
			
		||||
            }));
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
            res.writeHead(500, {
 | 
			
		||||
                'Content-Type': 'application/json'
 | 
			
		||||
            });
 | 
			
		||||
            res.end(JSON.stringify({
 | 
			
		||||
                message: err.message
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
	.get('/api/meet', async function (req, res, next) {
 | 
			
		||||
		if (req.query.token === '1445') {
 | 
			
		||||
			const time = cache.get('lastMeetingTime');
 | 
			
		||||
			res.writeHead(200, {
 | 
			
		||||
				'Content-Type': 'application/json'
 | 
			
		||||
			});
 | 
			
		||||
			res.end(JSON.stringify({
 | 
			
		||||
				LastMeetingTime: time ? time.toJSON() : undefined
 | 
			
		||||
			}));
 | 
			
		||||
		} else {
 | 
			
		||||
			next();
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	.post('/api/meet', async function (req, res, next) {
 | 
			
		||||
		if (req.body.token === '1445') {
 | 
			
		||||
			const time = new Date();
 | 
			
		||||
			const success = cache.set('lastMeetingTime', time, 3600);
 | 
			
		||||
			if (success) {
 | 
			
		||||
				res.writeHead(200, {
 | 
			
		||||
					'Content-Type': 'application/json'
 | 
			
		||||
				});
 | 
			
		||||
				res.end(JSON.stringify({
 | 
			
		||||
					LastMeetingTime: time.toJSON()
 | 
			
		||||
				}));
 | 
			
		||||
			} else {
 | 
			
		||||
				res.writeHead(500, {
 | 
			
		||||
					'Content-Type': 'application/json'
 | 
			
		||||
				});
 | 
			
		||||
				res.end(JSON.stringify({
 | 
			
		||||
					Error: 'Failed to store meeting time in cache!'
 | 
			
		||||
				}));
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			next();
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	.get('/api/memo', async function (req, res, next) {
 | 
			
		||||
		if (req.query.token === '1445') {
 | 
			
		||||
			const memos = cache.get('memos') || [];
 | 
			
		||||
			res.writeHead(200, {
 | 
			
		||||
				'Content-Type': 'application/json'
 | 
			
		||||
			});
 | 
			
		||||
			res.end(JSON.stringify(memos));
 | 
			
		||||
		} else {
 | 
			
		||||
			next();
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	.post('/api/memo', async function (req, res, next) {
 | 
			
		||||
		if (req.body.token === '1445') {
 | 
			
		||||
			const memo = req.body.message;
 | 
			
		||||
			if (!memo) {
 | 
			
		||||
				res.writeHead(400, {
 | 
			
		||||
					'Content-Type': 'application/json'
 | 
			
		||||
				});
 | 
			
		||||
				res.end(JSON.stringify({
 | 
			
		||||
					Error: 'You must provide a memo message'
 | 
			
		||||
				}));
 | 
			
		||||
			}
 | 
			
		||||
			const memos = cache.get('memos') || [];
 | 
			
		||||
			memos.push({
 | 
			
		||||
				Time: new Date(),
 | 
			
		||||
				Message: memo
 | 
			
		||||
			});
 | 
			
		||||
			const success = cache.set('memos', memos);
 | 
			
		||||
			if (success) {
 | 
			
		||||
				res.writeHead(200, {
 | 
			
		||||
					'Content-Type': 'application/json'
 | 
			
		||||
				});
 | 
			
		||||
				res.end(JSON.stringify(memos));
 | 
			
		||||
			} else {
 | 
			
		||||
				res.writeHead(500, {
 | 
			
		||||
					'Content-Type': 'application/json'
 | 
			
		||||
				});
 | 
			
		||||
				res.end(JSON.stringify({
 | 
			
		||||
					Error: 'Failed to store memo in cache!'
 | 
			
		||||
				}));
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			next();
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
app.use(helmet())
 | 
			
		||||
    .use(cors())
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user