progress update
image uploading works hosted at deta space
This commit is contained in:
parent
d5bf0927a6
commit
f36b48f4ce
15 changed files with 479 additions and 69 deletions
1
app.js
1
app.js
|
|
@ -32,6 +32,7 @@ app.set("view engine", "ejs");
|
|||
passportInit();
|
||||
app.use(
|
||||
session({
|
||||
proxy: true,
|
||||
secret: process.env.SECRET_KEY,
|
||||
resave: false,
|
||||
saveUninitialized: true,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,26 @@
|
|||
const Message = require("../models/message.js");
|
||||
const User = require("../models/user.js");
|
||||
const asyncHandler = require("express-async-handler");
|
||||
|
||||
exports.index = asyncHandler(async (req, res, next) => {
|
||||
// if user is logged in
|
||||
if (req.user) {
|
||||
// gets messages addressed to user from database
|
||||
const DMs = await Message.find({ to: req.user.username }).lean().exec();
|
||||
let DMs = await Message.find({ to: req.user.username }).lean().exec();
|
||||
// replaces from field with actual user
|
||||
for (let i = 0; i < DMs.length; i++) {
|
||||
const user = await User.findOne({ username: DMs[i].from }).lean().exec();
|
||||
DMs[i].from = user;
|
||||
}
|
||||
// gets messages addressed to all chat from database
|
||||
const allChat = await Message.find({ to: "all" }).lean().exec();
|
||||
// replaces from field with actual user
|
||||
for (let z = 0; z < allChat.length; z++) {
|
||||
const user = await User.findOne({ username: allChat[z].from })
|
||||
.lean()
|
||||
.exec();
|
||||
allChat[z].from = user;
|
||||
}
|
||||
// render index page
|
||||
return res.render("index", {
|
||||
DMs: DMs,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
const Message = require("../models/message.js");
|
||||
const User = require("../models/user.js");
|
||||
const asyncHandler = require("express-async-handler");
|
||||
const { body, validationResult } = require("express-validator");
|
||||
const { default: mongoose } = require("mongoose");
|
||||
|
|
@ -7,6 +8,7 @@ exports.new_get = (req, res, next) => {
|
|||
res.render("newmsg", {
|
||||
user: req.user,
|
||||
errors: false,
|
||||
to: false,
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -26,6 +28,7 @@ exports.new_post = [
|
|||
res.render("newmsg", {
|
||||
errors: errors.array(),
|
||||
user: req.user,
|
||||
to: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
@ -49,9 +52,20 @@ exports.new_post = [
|
|||
}),
|
||||
];
|
||||
|
||||
exports.respond_get = (req, res, next) => {
|
||||
res.render("newmsg", {
|
||||
user: req.user,
|
||||
errors: false,
|
||||
to: req.params.recipient,
|
||||
});
|
||||
};
|
||||
|
||||
exports.get = asyncHandler(async (req, res, next) => {
|
||||
// find message
|
||||
const message = await Message.findById(req.params.messageID).lean().exec();
|
||||
let message = await Message.findById(req.params.messageID).lean().exec();
|
||||
// replace from field with actual user
|
||||
const user = await User.findOne({ username: message.from }).lean().exec();
|
||||
message.from = user;
|
||||
res.render("message", {
|
||||
message: message,
|
||||
user: req.user,
|
||||
|
|
|
|||
|
|
@ -1,15 +1,25 @@
|
|||
const fs = require("fs");
|
||||
const User = require("../models/user.js");
|
||||
const asyncHandler = require("express-async-handler");
|
||||
const { body, validationResult } = require("express-validator");
|
||||
const { default: mongoose } = require("mongoose");
|
||||
const bcrypt = require("bcryptjs");
|
||||
const passport = require("passport");
|
||||
const multer = require("multer");
|
||||
const storage = multer.memoryStorage();
|
||||
const upload = multer({
|
||||
storage: storage,
|
||||
limits: { fileSize: 1840000 },
|
||||
});
|
||||
|
||||
exports.new_get = (req, res, next) => {
|
||||
res.render("newuser", { errors: false });
|
||||
};
|
||||
|
||||
exports.new_post = [
|
||||
// this goes first as it replaces bodyparser to some extent
|
||||
upload.single("avatar"),
|
||||
|
||||
// Validate and sanitize fields
|
||||
body("username", "Please enter a username!")
|
||||
.trim()
|
||||
|
|
@ -48,14 +58,28 @@ exports.new_post = [
|
|||
});
|
||||
return;
|
||||
}
|
||||
if (!req.file) {
|
||||
const error = {
|
||||
msg: "Avatar not uploaded",
|
||||
};
|
||||
// add to errors array
|
||||
errArr = [error];
|
||||
// Render the creation form again with error message.
|
||||
res.render("newuser", {
|
||||
errors: errArr,
|
||||
});
|
||||
return;
|
||||
}
|
||||
// else data is valid
|
||||
// create new user with hashed password
|
||||
const user = new User({
|
||||
username: req.body.username,
|
||||
password: await bcrypt.hash(req.body.password, 10),
|
||||
_id: new mongoose.Types.ObjectId(),
|
||||
avatar: req.file.buffer,
|
||||
});
|
||||
|
||||
// save to mongo
|
||||
await user.save();
|
||||
|
||||
// saved. Redirect to login page
|
||||
|
|
@ -99,34 +123,37 @@ exports.put_get = asyncHandler(async (req, res, next) => {
|
|||
const user = await User.findById(req.params.userID).lean().exec();
|
||||
res.render("edituser", {
|
||||
user: user,
|
||||
errors: false,
|
||||
});
|
||||
});
|
||||
|
||||
exports.put = [
|
||||
// this goes first as it replaces bodyparser to some extent
|
||||
upload.single("avatar"),
|
||||
|
||||
// Validate and sanitize fields
|
||||
// username cannot be changed for security/impersonation reasons
|
||||
|
||||
body("oldpassword", "Please enter current password to authorize changes!")
|
||||
.trim()
|
||||
.escape()
|
||||
.isLength({ min: 1 }),
|
||||
.isLength({ min: 1 })
|
||||
.custom(async (value, { req }) => {
|
||||
const dbUser = await User.findById(req.params.userID).lean().exec();
|
||||
const match = await bcrypt.compare(value, dbUser.password);
|
||||
if (!match) {
|
||||
return Promise.reject();
|
||||
}
|
||||
})
|
||||
.withMessage("Incorrect password!"),
|
||||
|
||||
body("password", "Please enter new password!").optional().trim().escape(),
|
||||
|
||||
body("confirm", "Please confirm new password!")
|
||||
.optional()
|
||||
.trim()
|
||||
.escape()
|
||||
.custom((value, { req }) => {
|
||||
if (value !== req.body.password)
|
||||
throw new Error("Passwords don't match!");
|
||||
else return value;
|
||||
}),
|
||||
|
||||
// tbd: allow profile pic changes with multer
|
||||
|
||||
// Process request after validation and sanitization.
|
||||
asyncHandler(async (req, res, next) => {
|
||||
// find existing user in DB
|
||||
const dbUser = await User.findById(req.params.userID).lean().exec();
|
||||
|
||||
// Extract the validation errors from a request.
|
||||
const errors = validationResult(req);
|
||||
// if there are validation errors
|
||||
|
|
@ -134,23 +161,66 @@ exports.put = [
|
|||
// Render the creation form again with sanitized values/error messages.
|
||||
res.render("edituser", {
|
||||
errors: errors.array(),
|
||||
user: dbUser,
|
||||
});
|
||||
return;
|
||||
}
|
||||
// else data is valid
|
||||
// find existing user in DB
|
||||
const dbUser = User.findById(req.params.userID).lean().exec();
|
||||
|
||||
// make new user
|
||||
const user = new User({
|
||||
// ascertain which fields have been changed by the user
|
||||
let password = (image = false);
|
||||
let user = null;
|
||||
|
||||
// check for password field
|
||||
if (
|
||||
req.body.password &&
|
||||
req.body.password != "" &&
|
||||
req.body.password != "null" &&
|
||||
req.body.password !== null
|
||||
) {
|
||||
password = true;
|
||||
}
|
||||
// check for image
|
||||
if (req.file) image = true;
|
||||
|
||||
// if there is a password
|
||||
if (password) {
|
||||
// if there is an image
|
||||
if (image) {
|
||||
// make new user with new avatar and password
|
||||
user = new User({
|
||||
username: dbUser.username,
|
||||
password: await bcrypt.hash(req.body.password, 10),
|
||||
_id: dbUser._id,
|
||||
avatar: req.file.buffer,
|
||||
});
|
||||
}
|
||||
// if there is not an image
|
||||
else {
|
||||
// make new user with new password only
|
||||
user = new User({
|
||||
username: dbUser.username,
|
||||
password: await bcrypt.hash(req.body.password, 10),
|
||||
_id: dbUser._id,
|
||||
avatar: dbUser.avatar,
|
||||
});
|
||||
}
|
||||
}
|
||||
// if there is not a password but there is an image
|
||||
else if (image) {
|
||||
// make new user with new image only
|
||||
user = new User({
|
||||
username: dbUser.username,
|
||||
password: dbUser.password,
|
||||
_id: dbUser._id,
|
||||
avatar: req.file.buffer,
|
||||
});
|
||||
}
|
||||
// if nothing was passed, user stays null
|
||||
|
||||
// update user in DB to new user
|
||||
// update user in DB to new user if needed
|
||||
if (user != null) {
|
||||
await User.findByIdAndUpdate(dbUser._id, user, {});
|
||||
|
||||
// saved. logout and redirect to log in again
|
||||
req.logout((err) => {
|
||||
if (err) {
|
||||
|
|
@ -158,6 +228,21 @@ exports.put = [
|
|||
}
|
||||
res.redirect("/user/login");
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// if nothing updated, redirect to edit page with error
|
||||
const error = {
|
||||
msg: "Nothing updated",
|
||||
};
|
||||
// add to errors array
|
||||
errArr = [error];
|
||||
// render error
|
||||
res.render("edituser", {
|
||||
user: dbUser,
|
||||
errors: errArr,
|
||||
});
|
||||
return;
|
||||
}),
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ const UserSchema = new Schema({
|
|||
username: { type: String, required: true },
|
||||
password: { type: String, required: true },
|
||||
_id: { type: mongoose.ObjectId, required: true },
|
||||
avatar: { type: Buffer, required: true },
|
||||
});
|
||||
|
||||
// Virtual for user URL
|
||||
|
|
|
|||
145
package-lock.json
generated
145
package-lock.json
generated
|
|
@ -19,6 +19,7 @@
|
|||
"express-session": "^1.17.3",
|
||||
"express-validator": "^7.0.1",
|
||||
"mongoose": "^7.5.1",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"passport": "^0.6.0",
|
||||
"passport-local": "^1.0.0",
|
||||
"passport-local-mongoose": "^8.0.0"
|
||||
|
|
@ -157,6 +158,11 @@
|
|||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/append-field": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
|
||||
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="
|
||||
},
|
||||
"node_modules/array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
|
|
@ -246,6 +252,22 @@
|
|||
"node": ">=14.20.1"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-from": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
|
||||
},
|
||||
"node_modules/busboy": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
||||
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
|
||||
"dependencies": {
|
||||
"streamsearch": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.16.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
|
|
@ -311,6 +333,20 @@
|
|||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
||||
},
|
||||
"node_modules/concat-stream": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
|
||||
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
|
||||
"engines": [
|
||||
"node >= 0.8"
|
||||
],
|
||||
"dependencies": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^2.2.2",
|
||||
"typedarray": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
|
|
@ -343,6 +379,11 @@
|
|||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
||||
},
|
||||
"node_modules/core-util-is": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
|
|
@ -858,6 +899,11 @@
|
|||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
|
||||
},
|
||||
"node_modules/jake": {
|
||||
"version": "10.8.7",
|
||||
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz",
|
||||
|
|
@ -991,6 +1037,25 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/mkdirp": {
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.6"
|
||||
},
|
||||
"bin": {
|
||||
"mkdirp": "bin/cmd.js"
|
||||
}
|
||||
},
|
||||
"node_modules/mongodb": {
|
||||
"version": "5.8.1",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.8.1.tgz",
|
||||
|
|
@ -1111,6 +1176,23 @@
|
|||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/multer": {
|
||||
"version": "1.4.5-lts.1",
|
||||
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz",
|
||||
"integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==",
|
||||
"dependencies": {
|
||||
"append-field": "^1.0.0",
|
||||
"busboy": "^1.0.0",
|
||||
"concat-stream": "^1.5.2",
|
||||
"mkdirp": "^0.5.4",
|
||||
"object-assign": "^4.1.1",
|
||||
"type-is": "^1.6.4",
|
||||
"xtend": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/negotiator": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
||||
|
|
@ -1119,6 +1201,14 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.12.3",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
|
||||
|
|
@ -1232,6 +1322,11 @@
|
|||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
|
|
@ -1320,6 +1415,25 @@
|
|||
"resolved": "https://registry.npmjs.org/read-input/-/read-input-0.3.1.tgz",
|
||||
"integrity": "sha512-J1ZkWCnB4altU7RTe+62PSfa21FrEtfKyO9fuqR3yP8kZku3nIwaw2Krj383JC7egAIl5Zyz2w+EOu9uXH5HZw=="
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||
"dependencies": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
|
|
@ -1503,6 +1617,27 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/streamsearch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
||||
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
|
|
@ -1588,6 +1723,11 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/typedarray": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
|
||||
},
|
||||
"node_modules/uid-safe": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
|
||||
|
|
@ -1607,6 +1747,11 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"node_modules/utils-merge": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
"express-session": "^1.17.3",
|
||||
"express-validator": "^7.0.1",
|
||||
"mongoose": "^7.5.1",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"passport": "^0.6.0",
|
||||
"passport-local": "^1.0.0",
|
||||
"passport-local-mongoose": "^8.0.0"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ const message_controller = require("../controllers/message.js");
|
|||
router.get("/new", message_controller.new_get);
|
||||
router.post("/new", message_controller.new_post); // C
|
||||
|
||||
router.get("/new/:recipient", message_controller.respond_get);
|
||||
|
||||
// message functions
|
||||
router.get("/:messageID", message_controller.get); // R
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,14 @@
|
|||
type="button"
|
||||
class="btn btn-outline-light px-4 py-2"
|
||||
>
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<img
|
||||
src="data:image/image/png;base64,
|
||||
<%=user.avatar.toString('base64')%>"
|
||||
width="24px"
|
||||
/>
|
||||
<%= user.username %>
|
||||
</div>
|
||||
</a>
|
||||
</header>
|
||||
<div class="d-flex flex-column py-4 px-4 align-items-center">
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@
|
|||
<link rel="stylesheet" href="/stylesheets/index.css" />
|
||||
</head>
|
||||
<body class="bg-dark text-light">
|
||||
<% if (errors) { errors.forEach(error => { %>
|
||||
<p class="text-center bg-danger"><%= error.msg %></p>
|
||||
<% }) } %>
|
||||
<header
|
||||
class="d-flex w-100 align-items-center justify-content-between border-bottom mb-2 border-light py-2 px-4 w-100"
|
||||
>
|
||||
|
|
@ -15,15 +18,27 @@
|
|||
type="button"
|
||||
class="btn btn-outline-light px-4 py-2"
|
||||
>
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<img
|
||||
src="data:image/image/png;base64,
|
||||
<%=user.avatar.toString('base64')%>"
|
||||
width="24px"
|
||||
/>
|
||||
<%= user.username %>
|
||||
</div>
|
||||
</a>
|
||||
</header>
|
||||
<div class="d-flex flex-column py-4 px-4 align-items-center">
|
||||
<h2 class="mb-4">Editing <%= user.username %></h2>
|
||||
<form class="d-flex flex-column align-items-center w-50" method="post">
|
||||
<p>Required fields are labeled *</p>
|
||||
<form
|
||||
class="d-flex flex-column align-items-center w-50"
|
||||
method="post"
|
||||
enctype="multipart/form-data"
|
||||
>
|
||||
<div class="input-group mb-4" data-bs-theme="dark">
|
||||
<span class="input-group-text" id="oldpassword-desc"
|
||||
>Current Password:</span
|
||||
>Current Password*:</span
|
||||
>
|
||||
<input
|
||||
type="password"
|
||||
|
|
@ -34,9 +49,7 @@
|
|||
/>
|
||||
</div>
|
||||
<div class="input-group mb-4" data-bs-theme="dark">
|
||||
<span class="input-group-text" id="password-desc"
|
||||
>New Password (optional):</span
|
||||
>
|
||||
<span class="input-group-text" id="password-desc">New Password:</span>
|
||||
<input
|
||||
type="password"
|
||||
class="form-control"
|
||||
|
|
@ -46,15 +59,13 @@
|
|||
/>
|
||||
</div>
|
||||
<div class="input-group mb-4" data-bs-theme="dark">
|
||||
<span class="input-group-text" id="confirm-desc"
|
||||
>Confirm New Password (optional):</span
|
||||
>
|
||||
<span class="input-group-text" id="avatar-desc">New Avatar:</span>
|
||||
<input
|
||||
type="password"
|
||||
type="file"
|
||||
class="form-control"
|
||||
aria-label="confirm password"
|
||||
aria-describedby="confirm-desc"
|
||||
name="confirm"
|
||||
aria-label="avatar"
|
||||
aria-describedby="avatar-desc"
|
||||
name="avatar"
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-outline-light px-4 py-2">
|
||||
|
|
|
|||
|
|
@ -15,11 +15,18 @@
|
|||
type="button"
|
||||
class="btn btn-outline-light px-4 py-2"
|
||||
>
|
||||
<div class="d-flex align-items-center gap-4">
|
||||
<img
|
||||
src="data:image/image/png;base64,
|
||||
<%=user.avatar.toString('base64')%>"
|
||||
width="24px"
|
||||
/>
|
||||
<%= user.username %>
|
||||
</div>
|
||||
</a>
|
||||
</header>
|
||||
<div class="d-flex flex-row p-4 w-100 justify-content-between">
|
||||
<div class="d-flex flex-column w-50">
|
||||
<div class="d-flex flex-column w-50 pe-3">
|
||||
<center>
|
||||
<h1 class="fs-4">Direct Messages:</h1>
|
||||
</center>
|
||||
|
|
@ -27,17 +34,37 @@
|
|||
<a
|
||||
href="/msg/<%= DM._id %>"
|
||||
type="button"
|
||||
class="btn btn-outline-light p-2"
|
||||
class="btn btn-outline-light py-4"
|
||||
>
|
||||
<div class="d-flex align-items-between">
|
||||
<div
|
||||
class="d-flex flex-column align-items-center justify-content-center w-50"
|
||||
>
|
||||
<div class="d-flex align-items-center gap-4">
|
||||
<img
|
||||
src="data:image/image/png;base64,
|
||||
<%=DM.from.avatar.toString('base64')%>"
|
||||
width="48px"
|
||||
/>
|
||||
<p class="p-0 m-0 fs-3"><%= DM.from.username %></p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="d-flex flex-column w-50 align-items-center justify-content-center"
|
||||
>
|
||||
<p class="p-0 m-0">From: <%= DM.from %></p>
|
||||
<p class="p-0 m-0">Sent: <%= DM.date.toDateString() %></p>
|
||||
<p>Last Updated: <%= DM.updated %></p>
|
||||
<p><%= DM.text %></p>
|
||||
<p class="p-0 m-0">
|
||||
Last Updated: <%= DM.updated.toDateString() %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pb-3"></div>
|
||||
<p class="p-0 m-0"><%= DM.text %></p>
|
||||
</a>
|
||||
<div class="pb-4"></div>
|
||||
<% }) %>
|
||||
</div>
|
||||
<div class="d-flex flex-column w-50">
|
||||
<div class="d-flex flex-column w-50 ps-3">
|
||||
<center>
|
||||
<h1 class="fs-4">Public Messages:</h1>
|
||||
</center>
|
||||
|
|
@ -45,12 +72,32 @@
|
|||
<a
|
||||
href="/msg/<%= chat._id %>"
|
||||
type="button"
|
||||
class="btn btn-outline-light p-2"
|
||||
class="btn btn-outline-light py-4"
|
||||
>
|
||||
<div class="d-flex align-items-between">
|
||||
<div
|
||||
class="d-flex flex-column align-items-center justify-content-center w-50"
|
||||
>
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<img
|
||||
src="data:image/image/png;base64,
|
||||
<%=chat.from.avatar.toString('base64')%>"
|
||||
width="48px"
|
||||
/>
|
||||
<p class="p-0 m-0 fs-3"><%= chat.from.username %></p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="d-flex flex-column w-50 align-items-center justify-content-center"
|
||||
>
|
||||
<p class="p-0 m-0">From: <%= chat.from %></p>
|
||||
<p class="p-0 m-0">Sent: <%= chat.date.toDateString() %></p>
|
||||
<p>Last Updated: <%= chat.updated.toDateString() %></p>
|
||||
<p><%= chat.text %></p>
|
||||
<p class="p-0 m-0">
|
||||
Last Updated: <%= chat.updated.toDateString() %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pb-3"></div>
|
||||
<p class="p-0 m-0"><%= chat.text %></p>
|
||||
</a>
|
||||
<div class="pb-4"></div>
|
||||
<% }) %>
|
||||
|
|
|
|||
|
|
@ -15,17 +15,44 @@
|
|||
type="button"
|
||||
class="btn btn-outline-light px-4 py-2"
|
||||
>
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<img
|
||||
src="data:image/image/png;base64,
|
||||
<%=user.avatar.toString('base64')%>"
|
||||
width="24px"
|
||||
/>
|
||||
<%= user.username %>
|
||||
</div>
|
||||
</a>
|
||||
</header>
|
||||
<div class="d-flex flex-column py-4 px-4 align-items-center">
|
||||
<p>From: <%= message.from %></p>
|
||||
<p>Sent: <%= message.date.toDateString() %></p>
|
||||
<p>Last Updated: <%= message.updated.toDateString() %></p>
|
||||
<div class="pb-4"></div>
|
||||
<p>" <%= message.text %> "</p>
|
||||
<div class="d-flex align-items-around w-100">
|
||||
<div
|
||||
class="d-flex flex-column align-items-center justify-content-center w-50"
|
||||
>
|
||||
<div class="d-flex align-items-center gap-4">
|
||||
<img
|
||||
src="data:image/image/png;base64,
|
||||
<%=message.from.avatar.toString('base64')%>"
|
||||
width="48px"
|
||||
/>
|
||||
<p class="p-0 m-0 fs-3"><%= message.from.username %></p>
|
||||
</div>
|
||||
<% if (user.username === message.from) { %>
|
||||
</div>
|
||||
<div
|
||||
class="d-flex flex-column w-50 align-items-center justify-content-center"
|
||||
>
|
||||
<p class="p-0 m-0">Sent: <%= message.date.toDateString() %></p>
|
||||
<p class="p-0 m-0">
|
||||
Last Updated: <%= message.updated.toDateString() %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pb-5"></div>
|
||||
<p class="p-0 m-0">" <%= message.text %> "</p>
|
||||
</div>
|
||||
<div class="pb-4"></div>
|
||||
<% if (user.username === message.from.username) { %>
|
||||
<center>
|
||||
<a
|
||||
href="/msg/<%= message._id %>/edit"
|
||||
|
|
@ -35,6 +62,16 @@
|
|||
Edit Message
|
||||
</a>
|
||||
</center>
|
||||
<% } else { %>
|
||||
<center>
|
||||
<a
|
||||
href="/msg/new/<%= message.from.username %>"
|
||||
type="button"
|
||||
class="btn btn-outline-light px-4 py-2"
|
||||
>
|
||||
Respond
|
||||
</a>
|
||||
</center>
|
||||
<% } %>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,14 @@
|
|||
type="button"
|
||||
class="btn btn-outline-light px-4 py-2"
|
||||
>
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<img
|
||||
src="data:image/image/png;base64,
|
||||
<%=user.avatar.toString('base64')%>"
|
||||
width="24px"
|
||||
/>
|
||||
<%= user.username %>
|
||||
</div>
|
||||
</a>
|
||||
</header>
|
||||
<div class="d-flex flex-column py-4 px-4 align-items-center">
|
||||
|
|
@ -26,6 +33,16 @@
|
|||
<form class="d-flex flex-column align-items-center w-50" method="post">
|
||||
<div class="input-group mb-4" data-bs-theme="dark">
|
||||
<span class="input-group-text" id="to-desc">To:</span>
|
||||
<% if (to) { %>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
aria-label="recipient"
|
||||
aria-describedby="to-desc"
|
||||
name="to"
|
||||
value="<%= to %>"
|
||||
/>
|
||||
<% } else { %>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
|
|
@ -33,6 +50,7 @@
|
|||
aria-describedby="to-desc"
|
||||
name="to"
|
||||
/>
|
||||
<% } %>
|
||||
</div>
|
||||
<div class="input-group mb-4" data-bs-theme="dark">
|
||||
<span class="input-group-text" id="text-desc">Message:</span>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,11 @@
|
|||
<h1 class="logotext mb-4">b0ard</h1>
|
||||
</header>
|
||||
<h2 class="mb-4">New User</h2>
|
||||
<form class="d-flex flex-column align-items-center w-50" method="post">
|
||||
<form
|
||||
class="d-flex flex-column align-items-center w-50"
|
||||
method="post"
|
||||
enctype="multipart/form-data"
|
||||
>
|
||||
<div class="input-group mb-4" data-bs-theme="dark">
|
||||
<span class="input-group-text" id="username-desc">Username:</span>
|
||||
<input
|
||||
|
|
@ -47,6 +51,16 @@
|
|||
name="confirm"
|
||||
/>
|
||||
</div>
|
||||
<div class="input-group mb-4" data-bs-theme="dark">
|
||||
<span class="input-group-text" id="avatar-desc">Avatar:</span>
|
||||
<input
|
||||
type="file"
|
||||
class="form-control"
|
||||
aria-label="avatar"
|
||||
aria-describedby="avatar-desc"
|
||||
name="avatar"
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-outline-light px-4 py-2">
|
||||
Submit
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -15,12 +15,26 @@
|
|||
type="button"
|
||||
class="btn btn-outline-light px-4 py-2"
|
||||
>
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<img
|
||||
src="data:image/image/png;base64,
|
||||
<%=user.avatar.toString('base64')%>"
|
||||
width="24px"
|
||||
/>
|
||||
<%= currentUser.username %>
|
||||
</div>
|
||||
</a>
|
||||
</header>
|
||||
<div class="d-flex flex-column py-4 px-4 align-items-center">
|
||||
<h1><%= user.username %></h1>
|
||||
<p>One day there will be avatars here</p>
|
||||
<div class="d-flex align-items-center gap-5 mb-5">
|
||||
<img
|
||||
src="data:image/image/png;base64,
|
||||
<%=user.avatar.toString('base64')%>"
|
||||
width="120rem"
|
||||
class="border-light border p-2 rounded"
|
||||
/>
|
||||
<h1 class="text-decoration-underline"><%= user.username %></h1>
|
||||
</div>
|
||||
<% if (user.username === currentUser.username) { %>
|
||||
<a
|
||||
href="/user/<%= user._id %>/edit"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue