Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docker prep #17

Merged
merged 9 commits into from
Nov 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
npm-debug.log
30 changes: 30 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#SET NODE VERSION
FROM node:18.17.1 as builder

#CONTAINER WORKING DIRECTORY
WORKDIR /usr/src/app

#COPY FILES INTO CONTAINER AT /usr/src/app
COPY . .

#INSTALL ROOT PACKAGES
RUN npm install

#INSTALL CLIENT PACKAGES
RUN cd client && npm install && npm run build

#SERVE BUILT FILES
FROM node:18.17.1

#SET WORKING DIRECTORY
WORKDIR /usr/src/app

#COPY FROM BUILDER STAGE
COPY --from=builder /usr/src/app/client/build ./client/build
COPY --from=builder /usr/src/app/node_modules ./node_modules

#EXPOSE PORT
EXPOSE 80

#DEFAULT CMD TO SERVE BUILT FILES
CMD ["npx", "serve", "-s", "client/build", "-l", "80"]
21 changes: 21 additions & 0 deletions Dockerfile-dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#SET NODE VERSION
FROM node:18.17.1

#CONTAINER WORKING DIRECTORY
WORKDIR /usr/src/app

#COPY FILES INTO CONTANER AT /usr/src/app
COPY . .

#TYING TO EXPLICITLY COPY THE CLIENT FOLDER
COPY ./client /usr/src/app/client

#INSTALL ROOT PACKAGES
RUN npm install

#INSTAL CLIENT PACKAGES
RUN cd client && npm install

#EXPOSE THE WEBPACK-DEV-SERVER PORT
EXPOSE 3000

9 changes: 2 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,8 @@
## dev environment setup

- Clone the repo down to your local machine.
- Run **npm i** in the root directory.
- Run **npm i** in the root of the client folder.
- Before servers are spun up you will need to run the initial tailwind script.
- In the **client** folder run **npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch** in your terminal. This will run the inital css build. It will also leave it running and provide live compiles for any changes to styling.
- Open a new terminal and in the **root** run **npm run dev-ts**. This will spin up the backend server and a localhost render on 8080.
- In the **client** folder run **npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch** in your terminal. You will be prompted to install Tailwind - Choose YES. This will run the inital css build. It will also leave it running and provide live compiles for any changes to styling.
- Open a new terminal and in the **root** run **npm run docker-dev**. This will spin up the containerized backend server and a localhost render on 8080.

You will ned to set up the .env file. This should include **"NODE_ENV=development"** as well as any database connection strings, api keys, seeder phrases as required.



24 changes: 12 additions & 12 deletions client/src/pages/LandingPage.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import React from 'react';
import Login from '../components/Login/Login';
import React from "react";
import Login from "../components/Login/Login";

const LandingPage: React.FC = () => {
return (
<div className="min-h-screen bg-gray-100 flex flex-col items-center justify-center">
<h1 className="text-4xl font-extrabold mb-4">Code Hammers</h1>
<p className="text-lg mb-4 text-center px-4">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce
scelerisque iaculis libero.
</p>
<Login />
</div>
);
return (
<div className="min-h-screen bg-gray-100 flex flex-col items-center justify-center">
<h1 className="text-4xl font-extrabold mb-4">Code Hammers</h1>
<p className="text-lg mb-4 text-center px-4">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce
scelerisque iaculis libero.
</p>
<Login />
</div>
);
};

export default LandingPage;
16 changes: 10 additions & 6 deletions client/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module.exports = {
output: {
path: path.resolve(__dirname, "build"),
filename: "bundle.js",
publicPath: '/'
publicPath: "/",
},

mode: process.env.NODE_ENV,
Expand All @@ -19,6 +19,9 @@ module.exports = {
}),
],
devServer: {
//REQUIRED FOR DOCKER
host: "0.0.0.0",
port: 8080,
proxy: {
"/api": "http://localhost:3000",
},
Expand All @@ -28,10 +31,11 @@ module.exports = {
historyApiFallback: {
rewrites: [
{
from: /^\/app/, to: '/index.html'
}
]
}
from: /^\/app/,
to: "/index.html",
},
],
},
},
module: {
rules: [
Expand All @@ -57,7 +61,7 @@ module.exports = {

{
test: /\.(png|jpe?g|gif|webp)$/i,
type: 'asset/resource',
type: "asset/resource",
},
],
},
Expand Down
148 changes: 109 additions & 39 deletions dist/controllers/userController.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,58 +12,128 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.authUser = exports.registerUser = void 0;
const express_async_handler_1 = __importDefault(require("express-async-handler"));
exports.deleteUserByEmail = exports.getUserById = exports.authUser = exports.registerUser = void 0;
const userModel_1 = __importDefault(require("../models/userModel"));
const generateToken_1 = __importDefault(require("../utils/generateToken"));
// ENDPOINT POST api/users
// ENDPOINT POST api/users/register
// PURPOSE Register a new user
// ACCESS Public
const registerUser = (0, express_async_handler_1.default)((req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
const registerUser = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
const { name, email, password } = req.body;
const isValidEmail = email.match(/[\w\d\.]+@[a-z]+\.[\w]+$/gim);
if (!isValidEmail) {
return next();
}
const userExists = yield userModel_1.default.findOne({ email });
if (userExists) {
res.status(400).json({ message: "User already exists!" });
return;
}
const user = yield userModel_1.default.create({
name,
email,
password,
});
if (user) {
res.status(201).json({
_id: user._id,
name: user.name,
email: user.email,
token: (0, generateToken_1.default)(user._id.toString()),
try {
const isValidEmail = email.match(/[\w\d\.]+@[a-z]+\.[\w]+$/gim);
if (!isValidEmail) {
return res.status(400).json("Invalid Email");
}
const userExists = yield userModel_1.default.findOne({ email });
if (userExists) {
return res.status(400).json({ message: "User already exists!" });
}
const user = yield userModel_1.default.create({
name,
email,
password,
});
if (user) {
res.locals.user = {
_id: user._id,
name: user.name,
email: user.email,
token: (0, generateToken_1.default)(user._id.toString()),
};
return res.status(201).json(res.locals.user);
}
}
else {
res.status(400).json({ message: "Invalid user data!" });
catch (error) {
console.error("Error during user signup:", error);
return next({
log: "Express error in createUser Middleware",
status: 503,
message: { err: "An error occurred during sign-up" },
});
}
}));
});
exports.registerUser = registerUser;
// ENDPOINT POST api/users/login
// PURPOSE Authenticate User and get token
// ACCESS Public
const authUser = (0, express_async_handler_1.default)((req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
const authUser = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
const { email, password } = req.body;
const user = yield userModel_1.default.findOne({ email });
if (user && (yield user.matchPassword(password))) {
res.json({
_id: user._id,
name: user.name,
email: user.email,
token: (0, generateToken_1.default)(user._id.toString()),
});
const isValidEmail = email.match(/[\w\d\.]+@[a-z]+\.[\w]+$/gim);
if (!isValidEmail) {
return res.status(400).json({ msg: "Please enter a valid email" }); //TODO Move to global error handler
}
else {
res.status(400).json({ message: "Invalid email or password!" });
if (!email || !password) {
return res.status(400).json({ msg: "Email and password are required!" }); //TODO Move to global error handler
}
}));
try {
const user = yield userModel_1.default.findOne({ email });
if (!user) {
return res.status(401).json({ msg: "User not found!" }); //TODO Move to global error handler
}
if (user && (yield user.matchPassword(password))) {
res.locals.user = {
_id: user._id,
name: user.name,
email: user.email,
token: (0, generateToken_1.default)(user._id.toString()),
};
return res.status(200).json(res.locals.user);
}
else {
return res.status(401).json({ msg: "Incorrect password" }); //TODO Move to global error handler
}
}
catch (error) {
console.error("Error during user authentication:", error);
return next({
log: "Express error in createUser Middleware",
status: 503,
message: { err: "An error occurred during login" },
});
}
});
exports.authUser = authUser;
// ENDPOINT GET api/users/:userId
// PURPOSE Get user by id
// ACCESS Private
const getUserById = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
const { userId } = req.params;
try {
const user = yield userModel_1.default.findOne({ _id: userId });
if (!user) {
return res.status(401).json({ msg: "User not found!" }); //TODO Move to global error handler
}
res.locals.user = user;
return res.status(200).json(res.locals.user);
}
catch (error) {
return next({
log: "Express error in getUserById Middleware",
status: 500,
message: { err: "An error occurred during retrieval" },
});
}
});
exports.getUserById = getUserById;
// ENDPOINT DELETE api/users/:email
// PURPOSE Delete user by email
// ACCESS Private
const deleteUserByEmail = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
const { email } = req.params;
try {
const user = yield userModel_1.default.findOneAndRemove({ email });
if (!user) {
return res.status(404).json({ msg: "User not found!" }); //TODO Move to global error handler
}
return res.status(200).json({ msg: "User successfully deleted!" });
}
catch (error) {
return next({
log: "Express error in getUserByEmail Middleware",
status: 500,
message: { err: "An error occurred during removal" },
});
}
});
exports.deleteUserByEmail = deleteUserByEmail;
16 changes: 12 additions & 4 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.startServer = void 0;
const path_1 = __importDefault(require("path"));
const express_1 = __importDefault(require("express"));
const userRoutes_1 = __importDefault(require("./routes/userRoutes"));
const db_1 = __importDefault(require("./config/db"));
const errorMIddleware_1 = require("./middleware/errorMIddleware");
const dotenv_1 = __importDefault(require("dotenv"));
const errorControllers_1 = require("./controllers/errorControllers");
dotenv_1.default.config();
const app = (0, express_1.default)();
app.use(express_1.default.json());
Expand All @@ -23,7 +24,14 @@ else {
res.json({ message: "API Running - Hazzah!" });
});
}
app.use(errorMIddleware_1.notFound);
app.use(errorMIddleware_1.errorHandler);
app.use(errorControllers_1.notFound);
app.use(errorControllers_1.errorHandler);
const PORT = Number(process.env.PORT) || 3000;
app.listen(PORT, () => console.log(`Server running in ${process.env.NODE_ENV} mode on port ${PORT}`));
const startServer = () => {
return app.listen(PORT, () => console.log(`Server running in ${process.env.NODE_ENV} mode on port ${PORT}`));
};
exports.startServer = startServer;
if (require.main === module) {
(0, exports.startServer)();
}
exports.default = app;
10 changes: 4 additions & 6 deletions dist/routes/userRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const userController_1 = require("../controllers/userController");
const router = express_1.default.Router();
router.post('/login', userController_1.authUser, (res) => {
return res.status(200).json({ msg: "Successful login!" });
});
router.post('/', userController_1.registerUser, (res) => {
return res.status(200).json({ msg: "Successful register!" });
});
router.post("/login", userController_1.authUser);
router.post("/register", userController_1.registerUser);
router.delete("/:email", userController_1.deleteUserByEmail);
router.get("/:userId", userController_1.getUserById);
exports.default = router;
17 changes: 17 additions & 0 deletions docker-compose-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: "3"
services:
dev:
image: brok3turtl3/codehammers:latest
container_name: mm-ch-dev
ports:
- "8080:8080"
volumes:
- .:/usr/src/app
- node_modules:/usr/src/app/node_modules
- client_node_modules:/usr/src/app/client/node_modules
command: npm run dev-ts
environment:
- NODE_ENV=development
volumes:
node_modules:
client_node_modules:
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
"version": "1.0.0",
"description": "A social platform for Codesmith Alumni to continue mentoring and learning together.",
"main": "/dist/index.js",
"scripts": {
"scripts": {
"build": "tsc",
"test": "jest --detectOpenHandles --coverage",
"client": "cd client && npm start",
"server": "node server/index.ts",
"server-ts": "ts-node-dev server/index.ts",
"dev-ts": "concurrently --kill-others \"npm run server-ts\" \"npm run client\"",
"dev": "concurrently --kill-others \"npm run server\" \"npm run client\"",
"docker-dev": "docker-compose -f docker-compose-dev.yml up --build",
"test:client": "cd client && npm test",
"test:all": "concurrently \"npm test\" \"npm run test:client\""
},
Expand Down