dockerized the project for dev
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
# The first FROM is now a stage called build-stage
|
||||
|
||||
FROM node:20 AS build-stage
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN npm ci
|
||||
|
||||
RUN npm run build
|
||||
|
||||
# This is a new stage, everything before this is gone, except for the files that we want to COPY
|
||||
|
||||
FROM nginx:1.25-alpine
|
||||
|
||||
# COPY the directory dist from the build-stage to /usr/share/nginx/html
|
||||
# The target location here was found from the Docker hub page
|
||||
|
||||
COPY --from=build-stage /usr/src/app/build /usr/share/nginx/html
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "/static/css/main.cb2b37d1.css",
|
||||
"main.js": "/static/js/main.d19fb767.js",
|
||||
"index.html": "/index.html",
|
||||
"main.cb2b37d1.css.map": "/static/css/main.cb2b37d1.css.map",
|
||||
"main.d19fb767.js.map": "/static/js/main.d19fb767.js.map"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.cb2b37d1.css",
|
||||
"static/js/main.d19fb767.js"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<!doctype html><html lang="en"><head><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><script defer="defer" src="/static/js/main.d19fb767.js"></script><link href="/static/css/main.cb2b37d1.css" rel="stylesheet"></head><body><div id="root"></div></body></html>
|
||||
@@ -0,0 +1,2 @@
|
||||
.datePicker :hover{border-color:"#212121"}.datePicker :focus{border-color:"#1976d2";border-width:"2px"}.datePicker{background:"red";color:"red"}.colormebaby{background-color:"red";color:"red"}
|
||||
/*# sourceMappingURL=main.cb2b37d1.css.map*/
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"static/css/main.cb2b37d1.css","mappings":"AAAA,mBACE,sBACF,CACA,mBACE,sBAAuB,CACvB,kBACF,CACA,YAEE,gBAAgB,CADhB,WAEF,CAEA,aACE,sBAAsB,CACtB,WACF","sources":["App2.css"],"sourcesContent":[".datePicker :hover {\n border-color: \"#212121\";\n}\n.datePicker :focus {\n border-color: \"#1976d2\";\n border-width: \"2px\";\n}\n.datePicker{\n color:\"red\";\n background:\"red\";\n}\n\n.colormebaby{\n background-color:\"red\";\n color:\"red\"\n}\n"],"names":[],"sourceRoot":""}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,121 @@
|
||||
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react-dom.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react-is.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react-jsx-runtime.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* scheduler.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* use-sync-external-store-shim.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* use-sync-external-store-shim/with-selector.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @mui/styled-engine v5.13.2
|
||||
*
|
||||
* @license MIT
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @remix-run/router v1.7.2
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* React Router DOM v6.14.2
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* React Router v6.14.2
|
||||
*
|
||||
* Copyright (c) Remix Software Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE.md file in the root directory of this source tree.
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/** @license React v16.13.1
|
||||
* react-is.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,10 @@
|
||||
|
||||
FROM node:20
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN npm ci
|
||||
|
||||
CMD npm start
|
||||
@@ -0,0 +1,11 @@
|
||||
services:
|
||||
app:
|
||||
image: devcon-frontend-dev
|
||||
build:
|
||||
context: . # The context will pick this directory as the "build context"
|
||||
dockerfile: dev.Dockerfile # This will simply tell which dockerfile to read
|
||||
volumes:
|
||||
- ./:/usr/src/app # The path can be relative, so ./ is enough to say "the same location as the docker-compose.yml"
|
||||
ports:
|
||||
- 5173:3000
|
||||
container_name: devcon-front-dev
|
||||
@@ -0,0 +1,11 @@
|
||||
services:
|
||||
app:
|
||||
image: todo-front-dev
|
||||
build:
|
||||
context: . # The context will pick this directory as the "build context"
|
||||
dockerfile: dev.Dockerfile # This will simply tell which dockerfile to read
|
||||
volumes:
|
||||
- ./:/usr/src/app # The path can be relative, so ./ is enough to say "the same location as the docker-compose.yml"
|
||||
ports:
|
||||
- 5173:5173
|
||||
container_name: todo-front
|
||||
+1
-1
@@ -53,5 +53,5 @@
|
||||
"devDependencies": {
|
||||
"@types/uuid": "^9.0.2"
|
||||
},
|
||||
"proxy": "http://localhost:5000"
|
||||
"proxy": "http://server:5000"
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ const Navbar = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [anchorElNav, setAnchorElNav] = React.useState<null | HTMLElement>(
|
||||
null
|
||||
null,
|
||||
);
|
||||
const handleOpenNavMenu = (event: React.MouseEvent<HTMLElement>) => {
|
||||
setAnchorElNav(event.currentTarget);
|
||||
@@ -73,7 +73,7 @@ const Navbar = () => {
|
||||
<AdbIcon sx={{ display: { xs: "none", md: "flex" }, mr: 1 }} />
|
||||
{/*LOGO link for bi display*/}
|
||||
<Typography
|
||||
variant="h6"
|
||||
variant="h5"
|
||||
noWrap
|
||||
sx={{
|
||||
mr: 2,
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
const mongoose = require('mongoose');
|
||||
const config = require('config');
|
||||
const db = config.get('mongoURI');
|
||||
|
||||
const connectDB = async () => {
|
||||
try {
|
||||
await mongoose.connect(db, {
|
||||
useNewUrlParser: true,
|
||||
useUnifiedTopology: true
|
||||
});
|
||||
|
||||
console.log('MongoDB Connected...');
|
||||
} catch (err) {
|
||||
console.error(err.message);
|
||||
// Exit process with failure
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = connectDB;
|
||||
@@ -1,21 +0,0 @@
|
||||
import mongoose from "mongoose";
|
||||
import config from 'config'
|
||||
|
||||
const db = config.get('mongoURI');
|
||||
|
||||
const connectDB = async () => {
|
||||
try {
|
||||
if (typeof db === 'string')
|
||||
await mongoose.connect(db);
|
||||
|
||||
console.log('MongoDB Connected...');
|
||||
} catch (err: unknown) {
|
||||
if (typeof err === 'string')
|
||||
console.error(err)
|
||||
else if (err instanceof Error)
|
||||
console.error(err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
export default connectDB
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
services:
|
||||
app:
|
||||
image: devcon-frontend-dev
|
||||
build:
|
||||
context: ./client
|
||||
dockerfile: ./dev.Dockerfile
|
||||
ports:
|
||||
- 3000:3000
|
||||
volumes:
|
||||
- ./client:/usr/src/app
|
||||
|
||||
server:
|
||||
image: devcon-backend-dev
|
||||
build:
|
||||
context: ./server
|
||||
dockerfile: ./dev.Dockerfile
|
||||
ports:
|
||||
- 5000:5000
|
||||
volumes:
|
||||
- ./server:/usr/src/app
|
||||
environment:
|
||||
MONGO_URL: "mongodb://the_username:the_password@mongo:27017/the_database"
|
||||
|
||||
mongo:
|
||||
image: mongo
|
||||
ports:
|
||||
- 3456:27017
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: root
|
||||
MONGO_INITDB_ROOT_PASSWORD: example
|
||||
MONGO_INITDB_DATABASE: the_database
|
||||
volumes:
|
||||
- ./mongo/mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js
|
||||
- mongo_data:/data/db
|
||||
|
||||
volumes:
|
||||
mongo_data:
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
services:
|
||||
mongo:
|
||||
image: mongo
|
||||
ports:
|
||||
- 3456:27017
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: root
|
||||
MONGO_INITDB_ROOT_PASSWORD: example
|
||||
MONGO_INITDB_DATABASE: the_database
|
||||
|
||||
volumes:
|
||||
- ./mongo/mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js
|
||||
@@ -1,28 +0,0 @@
|
||||
const config = require('config');
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
module.exports = function (req, res, next) {
|
||||
|
||||
// Get token from header
|
||||
const token = req.header('x-auth-token');
|
||||
// Check if not token
|
||||
if (!token) {
|
||||
return res.status(401).json({ msg: 'No token, authorization denied' });
|
||||
}
|
||||
|
||||
// Verify token
|
||||
try {
|
||||
jwt.verify(token, config.get('jwtSecret'), (error, decoded) => {
|
||||
if (error) {
|
||||
return res.status(401).json({ msg: 'Token is not valid' });
|
||||
} else {
|
||||
req.user = decoded.user;
|
||||
next();
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('something wrong with auth middleware');
|
||||
res.status(500).json({ msg: 'Server Error' });
|
||||
}
|
||||
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
const mongoose = require('mongoose');
|
||||
// middleware to check for a valid object id
|
||||
const checkObjectId = (idToCheck) => (req, res, next) => {
|
||||
if (!mongoose.Types.ObjectId.isValid(req.params[idToCheck]))
|
||||
return res.status(400).json({ msg: 'Invalid ID' });
|
||||
next();
|
||||
};
|
||||
|
||||
module.exports = checkObjectId;
|
||||
@@ -1,52 +0,0 @@
|
||||
const mongoose = require("mongoose");
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const PostSchema = new Schema({
|
||||
user: {
|
||||
type: Schema.Types.ObjectId,
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
},
|
||||
avatar: {
|
||||
type: String,
|
||||
},
|
||||
likes: [
|
||||
{
|
||||
user: {
|
||||
type: Schema.Types.ObjectId,
|
||||
},
|
||||
},
|
||||
],
|
||||
comments: [
|
||||
{
|
||||
user: {
|
||||
type: Schema.Types.ObjectId,
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
},
|
||||
avatar: {
|
||||
type: String,
|
||||
},
|
||||
date: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
},
|
||||
},
|
||||
],
|
||||
date: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = mongoose.model("post", PostSchema);
|
||||
@@ -1,113 +0,0 @@
|
||||
const mongoose = require("mongoose");
|
||||
|
||||
const ProfileSchema = new mongoose.Schema({
|
||||
user: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "user",
|
||||
},
|
||||
company: {
|
||||
type: String,
|
||||
},
|
||||
website: {
|
||||
type: String,
|
||||
},
|
||||
location: {
|
||||
type: String,
|
||||
},
|
||||
status: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
skills: {
|
||||
type: [String],
|
||||
required: true,
|
||||
},
|
||||
bio: {
|
||||
type: String,
|
||||
},
|
||||
githubusername: {
|
||||
type: String,
|
||||
},
|
||||
experience: [
|
||||
{
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
company: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
location: {
|
||||
type: String,
|
||||
},
|
||||
from: {
|
||||
type: Date,
|
||||
required: true,
|
||||
},
|
||||
to: {
|
||||
type: Date,
|
||||
},
|
||||
current: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
],
|
||||
education: [
|
||||
{
|
||||
school: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
degree: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
fieldofstudy: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
from: {
|
||||
type: Date,
|
||||
required: true,
|
||||
},
|
||||
to: {
|
||||
type: Date,
|
||||
},
|
||||
current: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
],
|
||||
social: {
|
||||
youtube: {
|
||||
type: String,
|
||||
},
|
||||
twitter: {
|
||||
type: String,
|
||||
},
|
||||
facebook: {
|
||||
type: String,
|
||||
},
|
||||
linkedin: {
|
||||
type: String,
|
||||
},
|
||||
instagram: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
date: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = mongoose.model("profile", ProfileSchema);
|
||||
@@ -1,26 +0,0 @@
|
||||
const mongoose = require("mongoose");
|
||||
|
||||
const UserSchema = new mongoose.Schema({
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
password: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
avatar: {
|
||||
type: String,
|
||||
},
|
||||
date: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = mongoose.model("user", UserSchema);
|
||||
@@ -0,0 +1,15 @@
|
||||
db.createUser({
|
||||
user: "the_username",
|
||||
pwd: "the_password",
|
||||
roles: [
|
||||
{
|
||||
role: "dbOwner",
|
||||
db: "the_database",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
db.createCollection("todos");
|
||||
|
||||
db.todos.insert({ text: "Write code", done: true });
|
||||
db.todos.insert({ text: "Learn about containers", done: false });
|
||||
@@ -1,280 +0,0 @@
|
||||
const express = require('express');
|
||||
const axios = require('axios');
|
||||
const config = require('config');
|
||||
const router = express.Router();
|
||||
const auth = require('../../middleware/auth');
|
||||
const { check, validationResult } = require('express-validator');
|
||||
// bring in normalize to give us a proper url, regardless of what user entered
|
||||
const normalize = require('normalize-url');
|
||||
const checkObjectId = require('../../middleware/checkObjectId');
|
||||
|
||||
const Profile = require('../../models/Profile');
|
||||
const User = require('../../models/User');
|
||||
const Post = require('../../models/Post');
|
||||
// @route GET api/profile/me
|
||||
// @desc Get current users profile
|
||||
// @access Private
|
||||
router.get('/me', auth, async (req, res) => {
|
||||
try {
|
||||
const profile = await Profile.findOne({
|
||||
user: req.user.id
|
||||
}).populate('user', ['name', 'avatar']);
|
||||
|
||||
if (!profile) {
|
||||
return res.status(400).json({ msg: 'There is no profile for this user' });
|
||||
}
|
||||
|
||||
res.json(profile);
|
||||
} catch (err) {
|
||||
console.error(err.message);
|
||||
res.status(500).send('Server Error');
|
||||
}
|
||||
});
|
||||
|
||||
// @route POST api/profile
|
||||
// @desc Create or update user profile
|
||||
// @access Private
|
||||
router.post(
|
||||
'/',
|
||||
auth,
|
||||
check('status', 'Status is required').notEmpty(),
|
||||
check('skills', 'Skills is required').notEmpty(),
|
||||
async (req, res) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json({ errors: errors.array() });
|
||||
}
|
||||
|
||||
// destructure the request
|
||||
const {
|
||||
website,
|
||||
skills,
|
||||
youtube,
|
||||
twitter,
|
||||
instagram,
|
||||
linkedin,
|
||||
facebook,
|
||||
// spread the rest of the fields we don't need to check
|
||||
...rest
|
||||
} = req.body;
|
||||
|
||||
// build a profile
|
||||
const profileFields = {
|
||||
user: req.user.id,
|
||||
website:
|
||||
website && website !== ''
|
||||
? normalize(website, { forceHttps: true })
|
||||
: '',
|
||||
skills: Array.isArray(skills)
|
||||
? skills
|
||||
: skills.split(',').map((skill) => ' ' + skill.trim()),
|
||||
...rest
|
||||
};
|
||||
|
||||
// Build socialFields object
|
||||
const socialFields = { youtube, twitter, instagram, linkedin, facebook };
|
||||
|
||||
// normalize social fields to ensure valid url
|
||||
for (const [key, value] of Object.entries(socialFields)) {
|
||||
if (value && value.length > 0)
|
||||
socialFields[key] = normalize(value, { forceHttps: true });
|
||||
}
|
||||
// add to profileFields
|
||||
profileFields.social = socialFields;
|
||||
|
||||
try {
|
||||
// Using upsert option (creates new doc if no match is found):
|
||||
let profile = await Profile.findOneAndUpdate(
|
||||
{ user: req.user.id },
|
||||
{ $set: profileFields },
|
||||
{ new: true, upsert: true, setDefaultsOnInsert: true }
|
||||
);
|
||||
return res.json(profile);
|
||||
} catch (err) {
|
||||
console.error(err.message);
|
||||
return res.status(500).send('Server Error');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// @route GET api/profile
|
||||
// @desc Get all profiles
|
||||
// @access Public
|
||||
router.get('/', async (req, res) => {
|
||||
try {
|
||||
const profiles = await Profile.find().populate('user', ['name', 'avatar']);
|
||||
res.json(profiles);
|
||||
} catch (err) {
|
||||
console.error(err.message);
|
||||
res.status(500).send('Server Error');
|
||||
}
|
||||
});
|
||||
|
||||
// @route GET api/profile/user/:user_id
|
||||
// @desc Get profile by user ID
|
||||
// @access Public
|
||||
router.get(
|
||||
'/user/:user_id',
|
||||
checkObjectId('user_id'),
|
||||
async ({ params: { user_id } }, res) => {
|
||||
try {
|
||||
const profile = await Profile.findOne({
|
||||
user: user_id
|
||||
}).populate('user', ['name', 'avatar']);
|
||||
|
||||
if (!profile) return res.status(400).json({ msg: 'Profile not found' });
|
||||
|
||||
return res.json(profile);
|
||||
} catch (err) {
|
||||
console.error(err.message);
|
||||
return res.status(500).json({ msg: 'Server error' });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// @route DELETE api/profile
|
||||
// @desc Delete profile, user & posts
|
||||
// @access Private
|
||||
router.delete('/', auth, async (req, res) => {
|
||||
try {
|
||||
// Remove user posts
|
||||
// Remove profile
|
||||
// Remove user
|
||||
await Promise.all([
|
||||
Post.deleteMany({ user: req.user.id }),
|
||||
Profile.findOneAndRemove({ user: req.user.id }),
|
||||
User.findOneAndRemove({ _id: req.user.id })
|
||||
]);
|
||||
|
||||
res.json({ msg: 'User deleted' });
|
||||
} catch (err) {
|
||||
console.error(err.message);
|
||||
res.status(500).send('Server Error');
|
||||
}
|
||||
});
|
||||
|
||||
// @route PUT api/profile/experience
|
||||
// @desc Add profile experience
|
||||
// @access Private
|
||||
router.put(
|
||||
'/experience',
|
||||
auth,
|
||||
check('title', 'Title is required').notEmpty(),
|
||||
check('company', 'Company is required').notEmpty(),
|
||||
check('from', 'From date is required and needs to be from the past')
|
||||
.notEmpty()
|
||||
.custom((value, { req }) => (req.body.to ? value < req.body.to : true)),
|
||||
async (req, res) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json({ errors: errors.array() });
|
||||
}
|
||||
|
||||
try {
|
||||
const profile = await Profile.findOne({ user: req.user.id });
|
||||
|
||||
profile.experience.unshift(req.body);
|
||||
|
||||
await profile.save();
|
||||
|
||||
res.json(profile);
|
||||
} catch (err) {
|
||||
console.error(err.message);
|
||||
res.status(500).send('Server Error');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// @route DELETE api/profile/experience/:exp_id
|
||||
// @desc Delete experience from profile
|
||||
// @access Private
|
||||
|
||||
router.delete('/experience/:exp_id', auth, async (req, res) => {
|
||||
try {
|
||||
const foundProfile = await Profile.findOne({ user: req.user.id });
|
||||
|
||||
foundProfile.experience = foundProfile.experience.filter(
|
||||
(exp) => exp._id.toString() !== req.params.exp_id
|
||||
);
|
||||
|
||||
await foundProfile.save();
|
||||
return res.status(200).json(foundProfile);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(500).json({ msg: 'Server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// @route PUT api/profile/education
|
||||
// @desc Add profile education
|
||||
// @access Private
|
||||
router.put(
|
||||
'/education',
|
||||
auth,
|
||||
check('school', 'School is required').notEmpty(),
|
||||
check('degree', 'Degree is required').notEmpty(),
|
||||
check('fieldofstudy', 'Field of study is required').notEmpty(),
|
||||
check('from', 'From date is required and needs to be from the past')
|
||||
.notEmpty()
|
||||
.custom((value, { req }) => (req.body.to ? value < req.body.to : true)),
|
||||
async (req, res) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json({ errors: errors.array() });
|
||||
}
|
||||
|
||||
try {
|
||||
const profile = await Profile.findOne({ user: req.user.id });
|
||||
|
||||
profile.education.unshift(req.body);
|
||||
|
||||
await profile.save();
|
||||
|
||||
res.json(profile);
|
||||
} catch (err) {
|
||||
console.error(err.message);
|
||||
res.status(500).send('Server Error');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// @route DELETE api/profile/education/:edu_id
|
||||
// @desc Delete education from profile
|
||||
// @access Private
|
||||
|
||||
router.delete('/education/:edu_id', auth, async (req, res) => {
|
||||
try {
|
||||
const foundProfile = await Profile.findOne({ user: req.user.id });
|
||||
foundProfile.education = foundProfile.education.filter(
|
||||
(edu) => edu._id.toString() !== req.params.edu_id
|
||||
);
|
||||
await foundProfile.save();
|
||||
return res.status(200).json(foundProfile);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return res.status(500).json({ msg: 'Server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// @route GET api/profile/github/:username
|
||||
// @desc Get user repos from Github
|
||||
// @access Public
|
||||
router.get('/github/:username', async (req, res) => {
|
||||
try {
|
||||
const uri = encodeURI(
|
||||
`https://api.github.com/users/${req.params.username}/repos?per_page=5&sort=created:asc`
|
||||
);
|
||||
const headers = {
|
||||
'user-agent': 'node.js',
|
||||
Authorization: `token ${config.get('githubToken')}`
|
||||
};
|
||||
|
||||
const gitHubResponse = await axios.get(uri, { headers });
|
||||
return res.json(gitHubResponse.data);
|
||||
} catch (err) {
|
||||
console.error(err.message);
|
||||
return res.status(404).json({ msg: 'No Github profile found' });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@@ -1,83 +0,0 @@
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const gravatar = require("gravatar");
|
||||
const bcrypt = require("bcryptjs");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const config = require("config");
|
||||
const { check, validationResult } = require("express-validator");
|
||||
const User = require("../../models/User");
|
||||
const normalize = require('normalize-url');
|
||||
|
||||
// @route POST api/users
|
||||
// @desc Register user
|
||||
// @access Public
|
||||
router.post(
|
||||
"/",
|
||||
check("name", "Name is required").notEmpty(),
|
||||
check("email", "Please include a valid email").isEmail(),
|
||||
check(
|
||||
"password",
|
||||
"Please enter a password with 6 or more characters"
|
||||
).isLength({ min: 6 }),
|
||||
async (req, res) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json({ errors: errors.array() });
|
||||
}
|
||||
|
||||
const { name, email, password } = req.body;
|
||||
|
||||
try {
|
||||
let user = await User.findOne({ email });
|
||||
|
||||
if (user) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ errors: [{ msg: "User already exists" }] });
|
||||
}
|
||||
|
||||
const avatar = normalize(
|
||||
gravatar.url(email, {
|
||||
s: "200",
|
||||
r: "pg",
|
||||
d: "mm",
|
||||
}),
|
||||
{ forceHttps: true }
|
||||
);
|
||||
|
||||
user = new User({
|
||||
name,
|
||||
email,
|
||||
avatar,
|
||||
password,
|
||||
});
|
||||
|
||||
const salt = await bcrypt.genSalt(10);
|
||||
|
||||
user.password = await bcrypt.hash(password, salt);
|
||||
|
||||
await user.save();
|
||||
|
||||
const payload = {
|
||||
user: {
|
||||
id: user.id,
|
||||
},
|
||||
};
|
||||
|
||||
jwt.sign(
|
||||
payload,
|
||||
config.get("jwtSecret"),
|
||||
{ expiresIn: "5 days" },
|
||||
(err, token) => {
|
||||
if (err) throw err;
|
||||
res.json({ token });
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err.message);
|
||||
res.status(500).send("Server error");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,15 @@
|
||||
FROM node:20
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
|
||||
COPY --chown=node:node . .
|
||||
|
||||
RUN npm ci
|
||||
|
||||
ENV DEBUG=express:*
|
||||
|
||||
|
||||
USER node
|
||||
|
||||
CMD npm start
|
||||
@@ -0,0 +1,5 @@
|
||||
const MONGO_URL = process.env.MONGO_URL || undefined;
|
||||
|
||||
module.exports = {
|
||||
MONGO_URL,
|
||||
};
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
import mongoose from "mongoose";
|
||||
// import config from "config";
|
||||
const { MONGO_URL } = require("./config");
|
||||
|
||||
// const db = config.get('mongoURI');
|
||||
|
||||
const connectDB = async () => {
|
||||
try {
|
||||
if (typeof MONGO_URL === "string") await mongoose.connect(MONGO_URL);
|
||||
|
||||
console.log("MongoDB Connected...");
|
||||
} catch (err: unknown) {
|
||||
if (typeof err === "string") console.error(err);
|
||||
else if (err instanceof Error) {
|
||||
console.error(err.message);
|
||||
console.log(MONGO_URL);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
export default connectDB;
|
||||
@@ -0,0 +1,13 @@
|
||||
FROM node:20
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY --chown=node:node . .
|
||||
|
||||
RUN npm i
|
||||
|
||||
ENV DEBUG=express:*
|
||||
|
||||
USER node
|
||||
|
||||
CMD npm start server
|
||||
@@ -0,0 +1,25 @@
|
||||
services:
|
||||
mongo:
|
||||
image: mongo
|
||||
ports:
|
||||
- 3456:27017
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: root
|
||||
MONGO_INITDB_ROOT_PASSWORD: example
|
||||
MONGO_INITDB_DATABASE: the_database
|
||||
volumes:
|
||||
- ../mongo/mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js
|
||||
- mongo_data:/data/db
|
||||
server: # The name of the service, can be anything
|
||||
image: devcon-backend-dev # Declares which image to use
|
||||
build: . # Declares where to build if image is not found
|
||||
ports: # Declares the ports to publish
|
||||
- 5000:5000
|
||||
volumes:
|
||||
- ./.:/usr/src/app
|
||||
environment:
|
||||
MONGO_URL: "mongodb://the_username:the_password@mongo:27017/the_database"
|
||||
|
||||
|
||||
volumes:
|
||||
mongo_data:
|
||||
@@ -0,0 +1,20 @@
|
||||
services:
|
||||
app: # The name of the service, can be anything
|
||||
image: devcon-backend # Declares which image to use
|
||||
build: . # Declares where to build if image is not found
|
||||
ports: # Declares the ports to publish
|
||||
- 3000:3000
|
||||
mongo:
|
||||
image: mongo
|
||||
ports:
|
||||
- 3456:27017
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: root
|
||||
MONGO_INITDB_ROOT_PASSWORD: example
|
||||
MONGO_INITDB_DATABASE: the_database
|
||||
volumes:
|
||||
- ./mongo/mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js
|
||||
- mongo_data:/data/db
|
||||
|
||||
volumes:
|
||||
mongo_data:
|
||||
Reference in New Issue
Block a user