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();
|
passportInit();
|
||||||
app.use(
|
app.use(
|
||||||
session({
|
session({
|
||||||
|
proxy: true,
|
||||||
secret: process.env.SECRET_KEY,
|
secret: process.env.SECRET_KEY,
|
||||||
resave: false,
|
resave: false,
|
||||||
saveUninitialized: true,
|
saveUninitialized: true,
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,26 @@
|
||||||
const Message = require("../models/message.js");
|
const Message = require("../models/message.js");
|
||||||
|
const User = require("../models/user.js");
|
||||||
const asyncHandler = require("express-async-handler");
|
const asyncHandler = require("express-async-handler");
|
||||||
|
|
||||||
exports.index = asyncHandler(async (req, res, next) => {
|
exports.index = asyncHandler(async (req, res, next) => {
|
||||||
// if user is logged in
|
// if user is logged in
|
||||||
if (req.user) {
|
if (req.user) {
|
||||||
// gets messages addressed to user from database
|
// 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
|
// gets messages addressed to all chat from database
|
||||||
const allChat = await Message.find({ to: "all" }).lean().exec();
|
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
|
// render index page
|
||||||
return res.render("index", {
|
return res.render("index", {
|
||||||
DMs: DMs,
|
DMs: DMs,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
const Message = require("../models/message.js");
|
const Message = require("../models/message.js");
|
||||||
|
const User = require("../models/user.js");
|
||||||
const asyncHandler = require("express-async-handler");
|
const asyncHandler = require("express-async-handler");
|
||||||
const { body, validationResult } = require("express-validator");
|
const { body, validationResult } = require("express-validator");
|
||||||
const { default: mongoose } = require("mongoose");
|
const { default: mongoose } = require("mongoose");
|
||||||
|
|
@ -7,6 +8,7 @@ exports.new_get = (req, res, next) => {
|
||||||
res.render("newmsg", {
|
res.render("newmsg", {
|
||||||
user: req.user,
|
user: req.user,
|
||||||
errors: false,
|
errors: false,
|
||||||
|
to: false,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -26,6 +28,7 @@ exports.new_post = [
|
||||||
res.render("newmsg", {
|
res.render("newmsg", {
|
||||||
errors: errors.array(),
|
errors: errors.array(),
|
||||||
user: req.user,
|
user: req.user,
|
||||||
|
to: false,
|
||||||
});
|
});
|
||||||
return;
|
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) => {
|
exports.get = asyncHandler(async (req, res, next) => {
|
||||||
// find message
|
// 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", {
|
res.render("message", {
|
||||||
message: message,
|
message: message,
|
||||||
user: req.user,
|
user: req.user,
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,25 @@
|
||||||
|
const fs = require("fs");
|
||||||
const User = require("../models/user.js");
|
const User = require("../models/user.js");
|
||||||
const asyncHandler = require("express-async-handler");
|
const asyncHandler = require("express-async-handler");
|
||||||
const { body, validationResult } = require("express-validator");
|
const { body, validationResult } = require("express-validator");
|
||||||
const { default: mongoose } = require("mongoose");
|
const { default: mongoose } = require("mongoose");
|
||||||
const bcrypt = require("bcryptjs");
|
const bcrypt = require("bcryptjs");
|
||||||
const passport = require("passport");
|
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) => {
|
exports.new_get = (req, res, next) => {
|
||||||
res.render("newuser", { errors: false });
|
res.render("newuser", { errors: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.new_post = [
|
exports.new_post = [
|
||||||
|
// this goes first as it replaces bodyparser to some extent
|
||||||
|
upload.single("avatar"),
|
||||||
|
|
||||||
// Validate and sanitize fields
|
// Validate and sanitize fields
|
||||||
body("username", "Please enter a username!")
|
body("username", "Please enter a username!")
|
||||||
.trim()
|
.trim()
|
||||||
|
|
@ -48,14 +58,28 @@ exports.new_post = [
|
||||||
});
|
});
|
||||||
return;
|
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
|
// else data is valid
|
||||||
// create new user with hashed password
|
// create new user with hashed password
|
||||||
const user = new User({
|
const user = new User({
|
||||||
username: req.body.username,
|
username: req.body.username,
|
||||||
password: await bcrypt.hash(req.body.password, 10),
|
password: await bcrypt.hash(req.body.password, 10),
|
||||||
_id: new mongoose.Types.ObjectId(),
|
_id: new mongoose.Types.ObjectId(),
|
||||||
|
avatar: req.file.buffer,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// save to mongo
|
||||||
await user.save();
|
await user.save();
|
||||||
|
|
||||||
// saved. Redirect to login page
|
// 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();
|
const user = await User.findById(req.params.userID).lean().exec();
|
||||||
res.render("edituser", {
|
res.render("edituser", {
|
||||||
user: user,
|
user: user,
|
||||||
|
errors: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
exports.put = [
|
exports.put = [
|
||||||
|
// this goes first as it replaces bodyparser to some extent
|
||||||
|
upload.single("avatar"),
|
||||||
|
|
||||||
// Validate and sanitize fields
|
// Validate and sanitize fields
|
||||||
// username cannot be changed for security/impersonation reasons
|
// username cannot be changed for security/impersonation reasons
|
||||||
|
|
||||||
body("oldpassword", "Please enter current password to authorize changes!")
|
body("oldpassword", "Please enter current password to authorize changes!")
|
||||||
.trim()
|
.trim()
|
||||||
.escape()
|
.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("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.
|
// Process request after validation and sanitization.
|
||||||
asyncHandler(async (req, res, next) => {
|
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.
|
// Extract the validation errors from a request.
|
||||||
const errors = validationResult(req);
|
const errors = validationResult(req);
|
||||||
// if there are validation errors
|
// if there are validation errors
|
||||||
|
|
@ -134,30 +161,88 @@ exports.put = [
|
||||||
// Render the creation form again with sanitized values/error messages.
|
// Render the creation form again with sanitized values/error messages.
|
||||||
res.render("edituser", {
|
res.render("edituser", {
|
||||||
errors: errors.array(),
|
errors: errors.array(),
|
||||||
|
user: dbUser,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// else data is valid
|
// else data is valid
|
||||||
// find existing user in DB
|
|
||||||
const dbUser = User.findById(req.params.userID).lean().exec();
|
|
||||||
|
|
||||||
// make new user
|
// ascertain which fields have been changed by the user
|
||||||
const user = new User({
|
let password = (image = false);
|
||||||
username: dbUser.username,
|
let user = null;
|
||||||
password: await bcrypt.hash(req.body.password, 10),
|
|
||||||
_id: dbUser._id,
|
|
||||||
});
|
|
||||||
|
|
||||||
// update user in DB to new user
|
// check for password field
|
||||||
await User.findByIdAndUpdate(dbUser._id, user, {});
|
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;
|
||||||
|
|
||||||
// saved. logout and redirect to log in again
|
// if there is a password
|
||||||
req.logout((err) => {
|
if (password) {
|
||||||
if (err) {
|
// if there is an image
|
||||||
return next(err);
|
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,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
res.redirect("/user/login");
|
// 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 if needed
|
||||||
|
if (user != null) {
|
||||||
|
await User.findByIdAndUpdate(dbUser._id, user, {});
|
||||||
|
// saved. logout and redirect to log in again
|
||||||
|
req.logout((err) => {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
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 },
|
username: { type: String, required: true },
|
||||||
password: { type: String, required: true },
|
password: { type: String, required: true },
|
||||||
_id: { type: mongoose.ObjectId, required: true },
|
_id: { type: mongoose.ObjectId, required: true },
|
||||||
|
avatar: { type: Buffer, required: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
// Virtual for user URL
|
// Virtual for user URL
|
||||||
|
|
|
||||||
145
package-lock.json
generated
145
package-lock.json
generated
|
|
@ -19,6 +19,7 @@
|
||||||
"express-session": "^1.17.3",
|
"express-session": "^1.17.3",
|
||||||
"express-validator": "^7.0.1",
|
"express-validator": "^7.0.1",
|
||||||
"mongoose": "^7.5.1",
|
"mongoose": "^7.5.1",
|
||||||
|
"multer": "^1.4.5-lts.1",
|
||||||
"passport": "^0.6.0",
|
"passport": "^0.6.0",
|
||||||
"passport-local": "^1.0.0",
|
"passport-local": "^1.0.0",
|
||||||
"passport-local-mongoose": "^8.0.0"
|
"passport-local-mongoose": "^8.0.0"
|
||||||
|
|
@ -157,6 +158,11 @@
|
||||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
"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": {
|
"node_modules/array-flatten": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||||
|
|
@ -246,6 +252,22 @@
|
||||||
"node": ">=14.20.1"
|
"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": {
|
"node_modules/bytes": {
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
"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": {
|
"node_modules/content-disposition": {
|
||||||
"version": "0.5.4",
|
"version": "0.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
"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": {
|
"node_modules/debug": {
|
||||||
"version": "2.6.9",
|
"version": "2.6.9",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
|
@ -858,6 +899,11 @@
|
||||||
"node": ">=0.12.0"
|
"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": {
|
"node_modules/jake": {
|
||||||
"version": "10.8.7",
|
"version": "10.8.7",
|
||||||
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz",
|
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz",
|
||||||
|
|
@ -991,6 +1037,25 @@
|
||||||
"node": "*"
|
"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": {
|
"node_modules/mongodb": {
|
||||||
"version": "5.8.1",
|
"version": "5.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.8.1.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
"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": {
|
"node_modules/negotiator": {
|
||||||
"version": "0.6.3",
|
"version": "0.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
||||||
|
|
@ -1119,6 +1201,14 @@
|
||||||
"node": ">= 0.6"
|
"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": {
|
"node_modules/object-inspect": {
|
||||||
"version": "1.12.3",
|
"version": "1.12.3",
|
||||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
|
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
|
||||||
|
|
@ -1232,6 +1322,11 @@
|
||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
"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": {
|
"node_modules/proxy-addr": {
|
||||||
"version": "2.0.7",
|
"version": "2.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/read-input/-/read-input-0.3.1.tgz",
|
||||||
"integrity": "sha512-J1ZkWCnB4altU7RTe+62PSfa21FrEtfKyO9fuqR3yP8kZku3nIwaw2Krj383JC7egAIl5Zyz2w+EOu9uXH5HZw=="
|
"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": {
|
"node_modules/require-directory": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||||
|
|
@ -1503,6 +1617,27 @@
|
||||||
"node": ">= 0.8"
|
"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": {
|
"node_modules/string-width": {
|
||||||
"version": "4.2.3",
|
"version": "4.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||||
|
|
@ -1588,6 +1723,11 @@
|
||||||
"node": ">= 0.6"
|
"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": {
|
"node_modules/uid-safe": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
|
||||||
|
|
@ -1607,6 +1747,11 @@
|
||||||
"node": ">= 0.8"
|
"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": {
|
"node_modules/utils-merge": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
"express-session": "^1.17.3",
|
"express-session": "^1.17.3",
|
||||||
"express-validator": "^7.0.1",
|
"express-validator": "^7.0.1",
|
||||||
"mongoose": "^7.5.1",
|
"mongoose": "^7.5.1",
|
||||||
|
"multer": "^1.4.5-lts.1",
|
||||||
"passport": "^0.6.0",
|
"passport": "^0.6.0",
|
||||||
"passport-local": "^1.0.0",
|
"passport-local": "^1.0.0",
|
||||||
"passport-local-mongoose": "^8.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.get("/new", message_controller.new_get);
|
||||||
router.post("/new", message_controller.new_post); // C
|
router.post("/new", message_controller.new_post); // C
|
||||||
|
|
||||||
|
router.get("/new/:recipient", message_controller.respond_get);
|
||||||
|
|
||||||
// message functions
|
// message functions
|
||||||
router.get("/:messageID", message_controller.get); // R
|
router.get("/:messageID", message_controller.get); // R
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,14 @@
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-outline-light px-4 py-2"
|
class="btn btn-outline-light px-4 py-2"
|
||||||
>
|
>
|
||||||
<%= user.username %>
|
<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>
|
</a>
|
||||||
</header>
|
</header>
|
||||||
<div class="d-flex flex-column py-4 px-4 align-items-center">
|
<div class="d-flex flex-column py-4 px-4 align-items-center">
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,9 @@
|
||||||
<link rel="stylesheet" href="/stylesheets/index.css" />
|
<link rel="stylesheet" href="/stylesheets/index.css" />
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-dark text-light">
|
<body class="bg-dark text-light">
|
||||||
|
<% if (errors) { errors.forEach(error => { %>
|
||||||
|
<p class="text-center bg-danger"><%= error.msg %></p>
|
||||||
|
<% }) } %>
|
||||||
<header
|
<header
|
||||||
class="d-flex w-100 align-items-center justify-content-between border-bottom mb-2 border-light py-2 px-4 w-100"
|
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"
|
type="button"
|
||||||
class="btn btn-outline-light px-4 py-2"
|
class="btn btn-outline-light px-4 py-2"
|
||||||
>
|
>
|
||||||
<%= user.username %>
|
<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>
|
</a>
|
||||||
</header>
|
</header>
|
||||||
<div class="d-flex flex-column py-4 px-4 align-items-center">
|
<div class="d-flex flex-column py-4 px-4 align-items-center">
|
||||||
<h2 class="mb-4">Editing <%= user.username %></h2>
|
<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">
|
<div class="input-group mb-4" data-bs-theme="dark">
|
||||||
<span class="input-group-text" id="oldpassword-desc"
|
<span class="input-group-text" id="oldpassword-desc"
|
||||||
>Current Password:</span
|
>Current Password*:</span
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
|
|
@ -34,9 +49,7 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group mb-4" data-bs-theme="dark">
|
<div class="input-group mb-4" data-bs-theme="dark">
|
||||||
<span class="input-group-text" id="password-desc"
|
<span class="input-group-text" id="password-desc">New Password:</span>
|
||||||
>New Password (optional):</span
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
|
|
@ -46,15 +59,13 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group mb-4" data-bs-theme="dark">
|
<div class="input-group mb-4" data-bs-theme="dark">
|
||||||
<span class="input-group-text" id="confirm-desc"
|
<span class="input-group-text" id="avatar-desc">New Avatar:</span>
|
||||||
>Confirm New Password (optional):</span
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="file"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
aria-label="confirm password"
|
aria-label="avatar"
|
||||||
aria-describedby="confirm-desc"
|
aria-describedby="avatar-desc"
|
||||||
name="confirm"
|
name="avatar"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-outline-light px-4 py-2">
|
<button type="submit" class="btn btn-outline-light px-4 py-2">
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,18 @@
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-outline-light px-4 py-2"
|
class="btn btn-outline-light px-4 py-2"
|
||||||
>
|
>
|
||||||
<%= user.username %>
|
<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>
|
</a>
|
||||||
</header>
|
</header>
|
||||||
<div class="d-flex flex-row p-4 w-100 justify-content-between">
|
<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>
|
<center>
|
||||||
<h1 class="fs-4">Direct Messages:</h1>
|
<h1 class="fs-4">Direct Messages:</h1>
|
||||||
</center>
|
</center>
|
||||||
|
|
@ -27,17 +34,37 @@
|
||||||
<a
|
<a
|
||||||
href="/msg/<%= DM._id %>"
|
href="/msg/<%= DM._id %>"
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-outline-light p-2"
|
class="btn btn-outline-light py-4"
|
||||||
>
|
>
|
||||||
<p class="p-0 m-0">From: <%= DM.from %></p>
|
<div class="d-flex align-items-between">
|
||||||
<p class="p-0 m-0">Sent: <%= DM.date.toDateString() %></p>
|
<div
|
||||||
<p>Last Updated: <%= DM.updated %></p>
|
class="d-flex flex-column align-items-center justify-content-center w-50"
|
||||||
<p><%= DM.text %></p>
|
>
|
||||||
|
<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">Sent: <%= DM.date.toDateString() %></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>
|
</a>
|
||||||
<div class="pb-4"></div>
|
<div class="pb-4"></div>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex flex-column w-50">
|
<div class="d-flex flex-column w-50 ps-3">
|
||||||
<center>
|
<center>
|
||||||
<h1 class="fs-4">Public Messages:</h1>
|
<h1 class="fs-4">Public Messages:</h1>
|
||||||
</center>
|
</center>
|
||||||
|
|
@ -45,12 +72,32 @@
|
||||||
<a
|
<a
|
||||||
href="/msg/<%= chat._id %>"
|
href="/msg/<%= chat._id %>"
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-outline-light p-2"
|
class="btn btn-outline-light py-4"
|
||||||
>
|
>
|
||||||
<p class="p-0 m-0">From: <%= chat.from %></p>
|
<div class="d-flex align-items-between">
|
||||||
<p class="p-0 m-0">Sent: <%= chat.date.toDateString() %></p>
|
<div
|
||||||
<p>Last Updated: <%= chat.updated.toDateString() %></p>
|
class="d-flex flex-column align-items-center justify-content-center w-50"
|
||||||
<p><%= chat.text %></p>
|
>
|
||||||
|
<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">Sent: <%= chat.date.toDateString() %></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>
|
</a>
|
||||||
<div class="pb-4"></div>
|
<div class="pb-4"></div>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
|
|
|
||||||
|
|
@ -15,17 +15,44 @@
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-outline-light px-4 py-2"
|
class="btn btn-outline-light px-4 py-2"
|
||||||
>
|
>
|
||||||
<%= user.username %>
|
<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>
|
</a>
|
||||||
</header>
|
</header>
|
||||||
<div class="d-flex flex-column py-4 px-4 align-items-center">
|
<div class="d-flex flex-column py-4 px-4 align-items-center">
|
||||||
<p>From: <%= message.from %></p>
|
<div class="d-flex align-items-around w-100">
|
||||||
<p>Sent: <%= message.date.toDateString() %></p>
|
<div
|
||||||
<p>Last Updated: <%= message.updated.toDateString() %></p>
|
class="d-flex flex-column align-items-center justify-content-center w-50"
|
||||||
<div class="pb-4"></div>
|
>
|
||||||
<p>" <%= message.text %> "</p>
|
<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>
|
||||||
|
</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>
|
||||||
<% if (user.username === message.from) { %>
|
<div class="pb-4"></div>
|
||||||
|
<% if (user.username === message.from.username) { %>
|
||||||
<center>
|
<center>
|
||||||
<a
|
<a
|
||||||
href="/msg/<%= message._id %>/edit"
|
href="/msg/<%= message._id %>/edit"
|
||||||
|
|
@ -35,6 +62,16 @@
|
||||||
Edit Message
|
Edit Message
|
||||||
</a>
|
</a>
|
||||||
</center>
|
</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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,14 @@
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-outline-light px-4 py-2"
|
class="btn btn-outline-light px-4 py-2"
|
||||||
>
|
>
|
||||||
<%= user.username %>
|
<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>
|
</a>
|
||||||
</header>
|
</header>
|
||||||
<div class="d-flex flex-column py-4 px-4 align-items-center">
|
<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">
|
<form class="d-flex flex-column align-items-center w-50" method="post">
|
||||||
<div class="input-group mb-4" data-bs-theme="dark">
|
<div class="input-group mb-4" data-bs-theme="dark">
|
||||||
<span class="input-group-text" id="to-desc">To:</span>
|
<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
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
|
|
@ -33,6 +50,7 @@
|
||||||
aria-describedby="to-desc"
|
aria-describedby="to-desc"
|
||||||
name="to"
|
name="to"
|
||||||
/>
|
/>
|
||||||
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group mb-4" data-bs-theme="dark">
|
<div class="input-group mb-4" data-bs-theme="dark">
|
||||||
<span class="input-group-text" id="text-desc">Message:</span>
|
<span class="input-group-text" id="text-desc">Message:</span>
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,11 @@
|
||||||
<h1 class="logotext mb-4">b0ard</h1>
|
<h1 class="logotext mb-4">b0ard</h1>
|
||||||
</header>
|
</header>
|
||||||
<h2 class="mb-4">New User</h2>
|
<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">
|
<div class="input-group mb-4" data-bs-theme="dark">
|
||||||
<span class="input-group-text" id="username-desc">Username:</span>
|
<span class="input-group-text" id="username-desc">Username:</span>
|
||||||
<input
|
<input
|
||||||
|
|
@ -47,6 +51,16 @@
|
||||||
name="confirm"
|
name="confirm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</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">
|
<button type="submit" class="btn btn-outline-light px-4 py-2">
|
||||||
Submit
|
Submit
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,26 @@
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-outline-light px-4 py-2"
|
class="btn btn-outline-light px-4 py-2"
|
||||||
>
|
>
|
||||||
<%= currentUser.username %>
|
<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>
|
</a>
|
||||||
</header>
|
</header>
|
||||||
<div class="d-flex flex-column py-4 px-4 align-items-center">
|
<div class="d-flex flex-column py-4 px-4 align-items-center">
|
||||||
<h1><%= user.username %></h1>
|
<div class="d-flex align-items-center gap-5 mb-5">
|
||||||
<p>One day there will be avatars here</p>
|
<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) { %>
|
<% if (user.username === currentUser.username) { %>
|
||||||
<a
|
<a
|
||||||
href="/user/<%= user._id %>/edit"
|
href="/user/<%= user._id %>/edit"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue