dockerized the project for dev

This commit is contained in:
QkoSad
2024-09-06 16:27:48 +03:00
parent 8e83b6b8df
commit 04ae8b7be8
47 changed files with 363 additions and 635 deletions
+20
View File
@@ -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
+13
View File
@@ -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"
]
}
+1
View File
@@ -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
+10
View File
@@ -0,0 +1,10 @@
FROM node:20
WORKDIR /usr/src/app
COPY . .
RUN npm ci
CMD npm start
+11
View File
@@ -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
+11
View File
@@ -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
View File
@@ -53,5 +53,5 @@
"devDependencies": {
"@types/uuid": "^9.0.2"
},
"proxy": "http://localhost:5000"
"proxy": "http://server:5000"
}
+2 -2
View File
@@ -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,
-20
View File
@@ -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;
-21
View File
@@ -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
+39
View File
@@ -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:
+12
View File
@@ -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
-28
View File
@@ -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' });
}
};
-9
View File
@@ -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;
-52
View File
@@ -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);
-113
View File
@@ -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);
-26
View File
@@ -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);
+15
View File
@@ -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 });
-280
View File
@@ -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;
-83
View File
@@ -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;
+15
View File
@@ -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
+5
View File
@@ -0,0 +1,5 @@
const MONGO_URL = process.env.MONGO_URL || undefined;
module.exports = {
MONGO_URL,
};
+22
View File
@@ -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;
+13
View File
@@ -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
+25
View File
@@ -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:
+20
View File
@@ -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:
View File
View File
View File