Merge remote-tracking branch 'upstream/master' into feat/redirect-on-no-admin
This commit is contained in:
commit
b563c44f38
16 files changed
+431
-134
No files matched your search
@@ -1,6 +1,6 @@
|
||||
.progress-bar-container{
|
||||
background-color: #fafafa;
|
||||
padding: var(--env-var-spacing-1-plus);
|
||||
.progress-bar-container {
|
||||
background-color: #fafafa;
|
||||
padding: var(--env-var-spacing-1-plus);
|
||||
}
|
||||
.progress-bar-container h2.MuiTypography-root,
|
||||
.progress-bar-container p.MuiTypography-root {
|
||||
@@ -10,9 +10,22 @@
|
||||
.progress-bar-container p.MuiTypography-root {
|
||||
opacity: 0.6;
|
||||
}
|
||||
.progress-bar-container p.MuiTypography-root:has(span){
|
||||
font-size: 12px;
|
||||
.progress-bar-container p.MuiTypography-root:has(span) {
|
||||
font-size: 12px;
|
||||
}
|
||||
.progress-bar-container p.MuiTypography-root span {
|
||||
padding-left: 2px;
|
||||
}
|
||||
padding-left: 2px;
|
||||
}
|
||||
.progress-bar-container:has(p.input-error){
|
||||
border-color: var(--env-var-color-24);
|
||||
padding: 8px var(--env-var-spacing-1-plus);
|
||||
}
|
||||
.progress-bar-container p.input-error{
|
||||
color: var(--env-var-color-24);
|
||||
opacity: 0.8;
|
||||
}
|
||||
.progress-bar-container:has(p.input-error)>.MuiStack-root>svg{
|
||||
fill: var(--env-var-color-24);
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import ErrorOutlineOutlinedIcon from "@mui/icons-material/ErrorOutlineOutlined";
|
||||
import "./index.css";
|
||||
|
||||
/**
|
||||
@@ -18,10 +19,18 @@ import "./index.css";
|
||||
* @param {string} props.size - The size information for the progress item.
|
||||
* @param {number} props.progress - The current progress value (0-100).
|
||||
* @param {function} props.onClick - The function to handle click events on the remove button.
|
||||
* @param {string} props.error - Error message to display if there's an error (optional).
|
||||
* @returns {JSX.Element} The rendered component.
|
||||
*/
|
||||
|
||||
const ProgressUpload = ({ icon, label, size, progress = 0, onClick }) => {
|
||||
const ProgressUpload = ({
|
||||
icon,
|
||||
label,
|
||||
size,
|
||||
progress = 0,
|
||||
onClick,
|
||||
error,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Box
|
||||
@@ -34,8 +43,15 @@ const ProgressUpload = ({ icon, label, size, progress = 0, onClick }) => {
|
||||
border: `solid 1px ${theme.palette.otherColors.graishWhite}`,
|
||||
}}
|
||||
>
|
||||
<Stack direction="row" mb="10px" gap="10px" alignItems="flex-end">
|
||||
{icon ? (
|
||||
<Stack
|
||||
direction="row"
|
||||
mb={error ? "0" : "10px"}
|
||||
gap="10px"
|
||||
alignItems={error ? "center" : "flex-end"}
|
||||
>
|
||||
{error ? (
|
||||
<ErrorOutlineOutlinedIcon />
|
||||
) : icon ? (
|
||||
<IconButton
|
||||
sx={{
|
||||
backgroundColor: theme.palette.otherColors.white,
|
||||
@@ -50,26 +66,36 @@ const ProgressUpload = ({ icon, label, size, progress = 0, onClick }) => {
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<Box>
|
||||
<Typography variant="h4" component="h2" mb="5px">
|
||||
{label}
|
||||
{error ? (
|
||||
<Typography component="p" className="input-error">
|
||||
{error}
|
||||
</Typography>
|
||||
<Typography variant="h4" component="p">
|
||||
{size}
|
||||
</Typography>
|
||||
</Box>
|
||||
) : (
|
||||
<Box>
|
||||
<Typography component="h2" mb="5px">
|
||||
{error ? error : label}
|
||||
</Typography>
|
||||
<Typography component="p">{!error && size}</Typography>
|
||||
</Box>
|
||||
)}
|
||||
<IconButton
|
||||
onClick={onClick}
|
||||
sx={{
|
||||
alignSelf: "flex-start",
|
||||
ml: "auto",
|
||||
mr: "-5px",
|
||||
mt: "-5px",
|
||||
padding: "5px",
|
||||
"&:focus": {
|
||||
outline: "none",
|
||||
},
|
||||
}}
|
||||
sx={
|
||||
!error
|
||||
? {
|
||||
alignSelf: "flex-start",
|
||||
ml: "auto",
|
||||
mr: "-5px",
|
||||
mt: "-5px",
|
||||
padding: "5px",
|
||||
"&:focus": {
|
||||
outline: "none",
|
||||
},
|
||||
}
|
||||
: {
|
||||
ml: "auto",
|
||||
}
|
||||
}
|
||||
>
|
||||
<CloseIcon
|
||||
sx={{
|
||||
@@ -78,25 +104,29 @@ const ProgressUpload = ({ icon, label, size, progress = 0, onClick }) => {
|
||||
/>
|
||||
</IconButton>
|
||||
</Stack>
|
||||
<Stack direction="row" alignItems="center">
|
||||
<Box sx={{ width: "100%", mr: "10px" }}>
|
||||
<LinearProgress
|
||||
variant="determinate"
|
||||
value={progress}
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "10px",
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
maxWidth: "500px",
|
||||
backgroundColor: theme.palette.otherColors.graishWhite,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Typography variant="h4" component="p" sx={{ minWidth: "max-content" }}>
|
||||
{progress}
|
||||
<span>%</span>
|
||||
</Typography>
|
||||
</Stack>
|
||||
{!error ? (
|
||||
<Stack direction="row" alignItems="center">
|
||||
<Box sx={{ width: "100%", mr: "10px" }}>
|
||||
<LinearProgress
|
||||
variant="determinate"
|
||||
value={progress}
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "10px",
|
||||
borderRadius: `${theme.shape.borderRadius}px`,
|
||||
maxWidth: "500px",
|
||||
backgroundColor: theme.palette.otherColors.graishWhite,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Typography component="p" sx={{ minWidth: "max-content" }}>
|
||||
{progress}
|
||||
<span>%</span>
|
||||
</Typography>
|
||||
</Stack>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -107,6 +137,7 @@ ProgressUpload.propTypes = {
|
||||
size: PropTypes.string.isRequired, // Size information for the progress item
|
||||
progress: PropTypes.number.isRequired, // Current progress value (0-100)
|
||||
onClick: PropTypes.func.isRequired, // Function to handle click events on the remove button
|
||||
error: PropTypes.string, // Error message to display if there's an error (optional)
|
||||
};
|
||||
|
||||
export default ProgressUpload;
|
||||
@@ -7,7 +7,10 @@ import Button from "../../Button";
|
||||
import EmailTextField from "../../TextFields/Email/EmailTextField";
|
||||
import StringTextField from "../../TextFields/Text/TextField";
|
||||
import Avatar from "../../Avatar";
|
||||
import { editProfileValidation } from "../../../Validation/validation";
|
||||
import {
|
||||
editProfileValidation,
|
||||
imageValidation,
|
||||
} from "../../../Validation/validation";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { update } from "../../../Features/Auth/authSlice";
|
||||
import ImageField from "../../TextFields/Image";
|
||||
@@ -76,12 +79,30 @@ const ProfilePanel = () => {
|
||||
const [uploadProgress, setUploadProgress] = useState(0);
|
||||
const [isUploading, setIsUploading] = useState(false);
|
||||
const handlePicture = (event) => {
|
||||
clearError("picture");
|
||||
const pic = event.target.files[0];
|
||||
console.log(pic);
|
||||
//TODO - add setPicture state to localData
|
||||
setPicture({ name: pic.name, type: pic.type, size: formatBytes(pic.size) });
|
||||
setIsUploading(true);
|
||||
|
||||
const { error } = imageValidation.validate(
|
||||
{
|
||||
type: pic.type,
|
||||
size: pic.size,
|
||||
},
|
||||
{ abortEarly: false }
|
||||
);
|
||||
|
||||
if (error) {
|
||||
setErrors((prev) => {
|
||||
const updatedErrors = { ...prev };
|
||||
updatedErrors["picture"] = error.details[0].message;
|
||||
return updatedErrors;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
//TODO - add setPicture state to localData
|
||||
setPicture((prev) => ({ ...prev, src: URL.createObjectURL(pic) }));
|
||||
@@ -98,20 +119,28 @@ const ProfilePanel = () => {
|
||||
};
|
||||
const formatBytes = (bytes) => {
|
||||
if (bytes === 0) return "0 Bytes";
|
||||
const k = 1024;
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " MB";
|
||||
const megabytes = bytes / (1024 * 1024);
|
||||
return megabytes.toFixed(2) + " MB";
|
||||
};
|
||||
const clearError = (err) => {
|
||||
setErrors((prev) => {
|
||||
const updatedErrors = { ...prev };
|
||||
if (updatedErrors[err]) delete updatedErrors[err];
|
||||
return updatedErrors;
|
||||
});
|
||||
};
|
||||
const handleCancelUpload = () => {
|
||||
//TODO - add setPicture state to localData
|
||||
setPicture(null);
|
||||
setPicture();
|
||||
setUploadProgress(0);
|
||||
setIsUploading(false);
|
||||
clearError("picture");
|
||||
};
|
||||
const handleClosePictureModal = () => {
|
||||
setIsOpen("");
|
||||
setUploadProgress(0);
|
||||
setIsUploading(false);
|
||||
clearError("picture");
|
||||
};
|
||||
|
||||
//TODO - revisit once localData is set up properly
|
||||
@@ -353,7 +382,6 @@ const ProfilePanel = () => {
|
||||
aria-describedby="update-profile-picture"
|
||||
open={isModalOpen("picture")}
|
||||
onClose={handleClosePictureModal}
|
||||
disablePortal
|
||||
>
|
||||
<Stack
|
||||
sx={{
|
||||
@@ -387,6 +415,7 @@ const ProfilePanel = () => {
|
||||
size={picture?.size}
|
||||
progress={uploadProgress}
|
||||
onClick={handleCancelUpload}
|
||||
error={errors["picture"]}
|
||||
/>
|
||||
) : (
|
||||
""
|
||||
|
||||
@@ -1,13 +1,27 @@
|
||||
.image-field-wrapper h2.MuiTypography-root,
|
||||
.image-field-wrapper p.MuiTypography-root {
|
||||
.image-field-wrapper p.MuiTypography-root,
|
||||
.image-field-wrapper + p.MuiTypography-root,
|
||||
.MuiStack-root:has(#modal-update-picture) h1.MuiTypography-root {
|
||||
color: var(--env-var-color-2);
|
||||
}
|
||||
.MuiStack-root:has(#modal-update-picture) h1.MuiTypography-root {
|
||||
font-weight: 600;
|
||||
}
|
||||
.image-field-wrapper h2.MuiTypography-root,
|
||||
.MuiStack-root:has(#modal-update-picture) button,
|
||||
.MuiStack-root:has(#modal-update-picture) h1.MuiTypography-root {
|
||||
font-size: var(--env-var-font-size-medium);
|
||||
}
|
||||
.image-field-wrapper h2.MuiTypography-root {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.image-field-wrapper + p.MuiTypography-root {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.image-field-wrapper + p.MuiTypography-root,
|
||||
.image-field-wrapper p.MuiTypography-root {
|
||||
opacity: 0.8;
|
||||
opacity: 0.6;
|
||||
font-size: var(--env-var-font-size-small-plus);
|
||||
}
|
||||
.image-field-wrapper h2.MuiTypography-root span {
|
||||
color: var(--env-var-color-3);
|
||||
|
||||
@@ -27,77 +27,78 @@ const ImageField = ({ id, picture, onChange }) => {
|
||||
return (
|
||||
<>
|
||||
{!picture ? (
|
||||
<Box
|
||||
className="image-field-wrapper"
|
||||
mt="20px"
|
||||
sx={{
|
||||
position: "relative",
|
||||
height: "fit-content",
|
||||
border: "dashed",
|
||||
borderRadius: `${theme.shape.borderRadius}px`,
|
||||
borderColor: isDragging
|
||||
? theme.palette.primary.main
|
||||
: theme.palette.otherColors.graishWhite,
|
||||
borderWidth: "2px",
|
||||
transition: "0.2s",
|
||||
"&:hover": {
|
||||
borderColor: theme.palette.primary.main,
|
||||
backgroundColor: "hsl(215, 87%, 51%, 0.05)",
|
||||
},
|
||||
}}
|
||||
onDragEnter={handleDragEnter}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleDragLeave}
|
||||
>
|
||||
<TextField
|
||||
id={id}
|
||||
type="file"
|
||||
onChange={onChange}
|
||||
<>
|
||||
<Box
|
||||
className="image-field-wrapper"
|
||||
mt="20px"
|
||||
sx={{
|
||||
width: "100%",
|
||||
"& .MuiInputBase-input[type='file']": {
|
||||
opacity: 0,
|
||||
cursor: "pointer",
|
||||
maxWidth: "500px",
|
||||
minHeight: "175px"
|
||||
},
|
||||
"& fieldset": {
|
||||
padding: 0,
|
||||
border: "none",
|
||||
position: "relative",
|
||||
height: "fit-content",
|
||||
border: "dashed",
|
||||
borderRadius: `${theme.shape.borderRadius}px`,
|
||||
borderColor: isDragging
|
||||
? theme.palette.primary.main
|
||||
: theme.palette.otherColors.graishWhite,
|
||||
borderWidth: "2px",
|
||||
transition: "0.2s",
|
||||
"&:hover": {
|
||||
borderColor: theme.palette.primary.main,
|
||||
backgroundColor: "hsl(215, 87%, 51%, 0.05)",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Stack
|
||||
className="custom-file-text"
|
||||
alignItems="center"
|
||||
gap="10px"
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
zIndex: "-1",
|
||||
width: "100%",
|
||||
}}
|
||||
onDragEnter={handleDragEnter}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleDragLeave}
|
||||
>
|
||||
<IconButton
|
||||
<TextField
|
||||
id={id}
|
||||
type="file"
|
||||
onChange={onChange}
|
||||
sx={{
|
||||
pointerEvents: "none",
|
||||
borderRadius: `${theme.shape.borderRadius}px`,
|
||||
border: `solid ${theme.shape.borderThick}px ${theme.palette.otherColors.graishWhite}`,
|
||||
boxShadow: theme.shape.boxShadow,
|
||||
width: "100%",
|
||||
"& .MuiInputBase-input[type='file']": {
|
||||
opacity: 0,
|
||||
cursor: "pointer",
|
||||
maxWidth: "500px",
|
||||
minHeight: "175px",
|
||||
},
|
||||
"& fieldset": {
|
||||
padding: 0,
|
||||
border: "none",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Stack
|
||||
className="custom-file-text"
|
||||
alignItems="center"
|
||||
gap="4px"
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
zIndex: "-1",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<CloudUploadIcon />
|
||||
</IconButton>
|
||||
<Typography variant="h4" component="h2">
|
||||
<span>Click to upload</span> or drag and drop
|
||||
</Typography>
|
||||
<Typography variant="h4" component="p">
|
||||
(max. 800x400px)
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Box>
|
||||
<IconButton
|
||||
sx={{
|
||||
pointerEvents: "none",
|
||||
borderRadius: `${theme.shape.borderRadius}px`,
|
||||
border: `solid ${theme.shape.borderThick}px ${theme.palette.otherColors.graishWhite}`,
|
||||
boxShadow: theme.shape.boxShadow,
|
||||
}}
|
||||
>
|
||||
<CloudUploadIcon />
|
||||
</IconButton>
|
||||
<Typography component="h2">
|
||||
<span>Click to upload</span> or drag and drop
|
||||
</Typography>
|
||||
<Typography component="p">(maximum size: 3MB)</Typography>
|
||||
</Stack>
|
||||
</Box>
|
||||
<Typography component="p">Supported formats: JPG, PNG</Typography>
|
||||
</>
|
||||
) : (
|
||||
<Stack direction="row" justifyContent="center">
|
||||
<Box
|
||||
@@ -107,10 +108,9 @@ const ImageField = ({ id, picture, onChange }) => {
|
||||
borderRadius: "50%",
|
||||
overflow: "hidden",
|
||||
backgroundImage: `url(${picture})`,
|
||||
backgroundSize: "cover"
|
||||
backgroundSize: "cover",
|
||||
}}
|
||||
>
|
||||
</Box>
|
||||
></Box>
|
||||
</Stack>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -63,15 +63,6 @@ export const update = createAsyncThunk(
|
||||
}
|
||||
);
|
||||
|
||||
export const deleteAccount = createAsyncThunk(
|
||||
"auth/delete",
|
||||
async (form, thunkApi) => {
|
||||
try {
|
||||
//TODO
|
||||
} catch (error) {}
|
||||
}
|
||||
);
|
||||
|
||||
const handleAuthFulfilled = (state, action) => {
|
||||
state.isLoading = false;
|
||||
state.success = action.payload.success;
|
||||
|
||||
@@ -150,7 +150,23 @@ const createMonitorValidation = joi.object({
|
||||
}),
|
||||
});
|
||||
|
||||
const imageValidation = joi.object({
|
||||
type: joi.string().valid("image/jpeg", "image/png").messages({
|
||||
"any.only": "Invalid file format.",
|
||||
"string.empty": "File type required.",
|
||||
}),
|
||||
size: joi
|
||||
.number()
|
||||
.max(3 * 1024 * 1024)
|
||||
.messages({
|
||||
"number.base": "File size must be a number.",
|
||||
"number.max": "File size must be less than 3 MB.",
|
||||
"number.empty": "File size required.",
|
||||
}),
|
||||
});
|
||||
|
||||
export {
|
||||
imageValidation,
|
||||
createMonitorValidation,
|
||||
registerValidation,
|
||||
loginValidation,
|
||||
|
||||
@@ -151,6 +151,29 @@ const userEditController = async (req, res, next) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks to see if an admin account exists
|
||||
* @async
|
||||
* @param {Express.Request} req
|
||||
* @param {Express.Response} res
|
||||
* @returns {Promise<Express.Response>}
|
||||
*/
|
||||
|
||||
const checkAdminController = async (req, res) => {
|
||||
try {
|
||||
const adminExists = await req.db.checkAdmin(req, res);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.AUTH_ADMIN_EXISTS,
|
||||
data: adminExists,
|
||||
});
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a recovery token
|
||||
* @async
|
||||
@@ -238,6 +261,7 @@ module.exports = {
|
||||
registerController,
|
||||
loginController,
|
||||
userEditController,
|
||||
checkAdminController,
|
||||
recoveryRequestController,
|
||||
validateRecoveryTokenController,
|
||||
resetPasswordController,
|
||||
|
||||
+22
-1
@@ -32,7 +32,15 @@ const connect = async () => {
|
||||
*/
|
||||
const insertUser = async (req, res) => {
|
||||
try {
|
||||
const newUser = new UserModel({ ...req.body });
|
||||
const userData = { ...req.body };
|
||||
console.log(req.file);
|
||||
if (req.file) {
|
||||
userData.profileImage = {
|
||||
data: req.file.buffer,
|
||||
contentType: req.file.mimetype,
|
||||
};
|
||||
}
|
||||
const newUser = new UserModel(userData);
|
||||
await newUser.save();
|
||||
return await UserModel.findOne({ _id: newUser._id }).select("-password"); // .select() doesn't work with create, need to save then find
|
||||
} catch (error) {
|
||||
@@ -163,6 +171,18 @@ const resetPassword = async (req, res) => {
|
||||
}
|
||||
};
|
||||
|
||||
const checkAdmin = async (req, res) => {
|
||||
try {
|
||||
const admin = await UserModel.findOne({ role: "admin" });
|
||||
if (admin !== null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
//****************************************
|
||||
// Monitors
|
||||
//****************************************
|
||||
@@ -502,6 +522,7 @@ module.exports = {
|
||||
requestRecoveryToken,
|
||||
validateRecoveryToken,
|
||||
resetPassword,
|
||||
checkAdmin,
|
||||
getAllMonitors,
|
||||
getMonitorById,
|
||||
getMonitorsByUserId,
|
||||
|
||||
@@ -2,6 +2,7 @@ const logger = require("../utils/logger");
|
||||
const { errorMessages } = require("../utils/messages");
|
||||
|
||||
const handleErrors = (error, req, res, next) => {
|
||||
console.log(error);
|
||||
const status = error.status || 500;
|
||||
const message = error.message || errorMessages.FRIENDLY_ERROR;
|
||||
const service = error.service || errorMessages.UNKNOWN_SERVICE;
|
||||
|
||||
@@ -20,8 +20,9 @@ const UserSchema = mongoose.Schema(
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
profilePicUrl: {
|
||||
type: String,
|
||||
profileImage: {
|
||||
data: Buffer,
|
||||
contentType: String,
|
||||
},
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
|
||||
Generated
+149
@@ -21,6 +21,7 @@
|
||||
"jsonwebtoken": "9.0.2",
|
||||
"mailersend": "^2.2.0",
|
||||
"mongoose": "^8.3.3",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"ping": "0.4.4",
|
||||
"winston": "^3.13.0"
|
||||
},
|
||||
@@ -333,6 +334,12 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/aproba": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
|
||||
@@ -476,6 +483,12 @@
|
||||
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"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==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bullmq": {
|
||||
"version": "5.7.15",
|
||||
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.7.15.tgz",
|
||||
@@ -491,6 +504,17 @@
|
||||
"uuid": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"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",
|
||||
@@ -634,6 +658,51 @@
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"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"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^2.2.2",
|
||||
"typedarray": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-stream/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==",
|
||||
"license": "MIT",
|
||||
"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/concat-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==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/concat-stream/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==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||
@@ -676,6 +745,12 @@
|
||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"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==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cors": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||
@@ -1460,6 +1535,12 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/isomorphic-unfetch": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz",
|
||||
@@ -1743,6 +1824,15 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/minipass": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
|
||||
@@ -1954,6 +2044,36 @@
|
||||
"@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.2"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"license": "MIT",
|
||||
"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/multer/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==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.6"
|
||||
},
|
||||
"bin": {
|
||||
"mkdirp": "bin/cmd.js"
|
||||
}
|
||||
},
|
||||
"node_modules/negotiator": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
||||
@@ -2215,6 +2335,12 @@
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
@@ -2559,6 +2685,14 @@
|
||||
"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.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
@@ -2702,6 +2836,12 @@
|
||||
"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==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/undefsafe": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
|
||||
@@ -2834,6 +2974,15 @@
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"jsonwebtoken": "9.0.2",
|
||||
"mailersend": "^2.2.0",
|
||||
"mongoose": "^8.3.3",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"ping": "0.4.4",
|
||||
"winston": "^3.13.0"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
const router = require("express").Router();
|
||||
const { verifyJWT } = require("../middleware/verifyJWT");
|
||||
const multer = require("multer");
|
||||
const upload = multer();
|
||||
|
||||
const {
|
||||
registerController,
|
||||
@@ -8,12 +10,14 @@ const {
|
||||
recoveryRequestController,
|
||||
validateRecoveryTokenController,
|
||||
resetPasswordController,
|
||||
checkAdminController,
|
||||
} = require("../controllers/authController");
|
||||
|
||||
//Auth routes
|
||||
router.post("/register", registerController);
|
||||
router.post("/register", upload.single("profileImage"), registerController);
|
||||
router.post("/login", loginController);
|
||||
router.post("/user/:userId", verifyJWT, userEditController);
|
||||
router.get("/users/admin", checkAdminController);
|
||||
|
||||
//Recovery routes
|
||||
router.post("/recovery/request", recoveryRequestController);
|
||||
|
||||
@@ -56,6 +56,7 @@ const successMessages = {
|
||||
AUTH_CREATE_RECOVERY_TOKEN: "Recovery token created successfully",
|
||||
AUTH_VERIFY_RECOVERY_TOKEN: "Recovery token verified successfully",
|
||||
AUTH_RESET_PASSWORD: "Password reset successfully",
|
||||
AUTH_ADMIN_CHECK: "Admin check completed successfully",
|
||||
|
||||
// Check Controller
|
||||
CHECK_CREATE: "Check created successfully",
|
||||
|
||||
@@ -14,6 +14,7 @@ const registerValidation = joi.object({
|
||||
lastname: joi.string().required(),
|
||||
email: joi.string().email().required(),
|
||||
password: joi.string().min(8).required(),
|
||||
profileImage: joi.any(),
|
||||
role: joi.string().required(),
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user