-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
45d2eb1
commit 7274a95
Showing
66 changed files
with
9,232 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.env.production | ||
.env | ||
dist | ||
.DS_Store | ||
node_modules | ||
out | ||
yarn.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
node_modules | ||
dist | ||
npm-debug.log | ||
.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
GITHUB_CLIENT_ID= | ||
GITHUB_CLIENT_SECRET= | ||
ACCESS_TOKEN_SECRET= | ||
MONGO_URL=mongodb://localhost:27017/vstodo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
FROM node:14 | ||
|
||
# Create app directory | ||
WORKDIR /usr/src/app | ||
|
||
# Install app dependencies | ||
# A wildcard is used to ensure both package.json AND package-lock.json are copied | ||
# where available (npm@5+) | ||
COPY package.json ./ | ||
COPY yarn.lock ./ | ||
|
||
RUN yarn | ||
|
||
COPY . . | ||
COPY .env.production .env | ||
|
||
RUN yarn build | ||
|
||
ENV NODE_ENV production | ||
|
||
EXPOSE 3002 | ||
CMD [ "node", "dist/index.js" ] | ||
USER node |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
{ | ||
"name": "api", | ||
"version": "1.0.0", | ||
"description": "", | ||
"main": "index.js", | ||
"scripts": { | ||
"watch": "tsc -w", | ||
"build": "tsc", | ||
"dev": "nodemon dist/index.js" | ||
}, | ||
"keywords": [], | ||
"author": "", | ||
"license": "ISC", | ||
"dependencies": { | ||
"browserslist": "^4.16.3", | ||
"browserslist-useragent": "^3.0.3", | ||
"cors": "^2.8.5", | ||
"dotenv": "^8.2.0", | ||
"express": "^4.17.1", | ||
"jsonwebtoken": "^8.5.1", | ||
"mongoose": "^5.11.17", | ||
"passport": "^0.4.1", | ||
"passport-github": "^1.1.0", | ||
"uuid": "^8.3.2" | ||
}, | ||
"devDependencies": { | ||
"@types/cors": "^2.8.10", | ||
"@types/express": "^4.17.11", | ||
"@types/jsonwebtoken": "^8.5.0", | ||
"@types/mongoose": "^5.10.3", | ||
"@types/node": "^14.14.27", | ||
"@types/passport": "^1.0.6", | ||
"@types/passport-github": "^1.1.5", | ||
"@types/uuid": "^8.3.0", | ||
"nodemon": "^2.0.7", | ||
"typescript": "^4.1.5" | ||
}, | ||
"browserslist": [ | ||
"ie <= 11" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
require("dotenv").config(); | ||
// lib | ||
import express from "express"; | ||
import mongoose from "mongoose"; | ||
import passport from "passport"; | ||
import { Strategy as GithubStrategy } from "passport-github"; | ||
import { sign, verify } from "jsonwebtoken"; | ||
import cors from "cors"; | ||
|
||
// DB Models | ||
import User from "./models/User"; | ||
|
||
// routes | ||
import boardRoutes from "./routes/board"; | ||
import todoListRoutes from "./routes/todoList"; | ||
|
||
const main = async () => { | ||
console.log(process.env, "check env variables here"); | ||
const app = express(); | ||
passport.serializeUser((user: any, done) => { | ||
done(null, user.accessToken); | ||
}); | ||
app.use(cors({ origin: "*" })); | ||
app.use(passport.initialize()); | ||
app.use(express.json()); | ||
|
||
passport.use( | ||
new GithubStrategy( | ||
{ | ||
clientID: process.env.GITHUB_CLIENT_ID as string, | ||
clientSecret: process.env.GITHUB_CLIENT_SECRET as string, | ||
callbackURL: | ||
process.env.NODE_ENV === "production" | ||
? process.env.CALLBACK_URL | ||
: "http://localhost:3002/auth/github/callback", | ||
}, | ||
async (_, __, profile, cb) => { | ||
let user = await User.findOne({ githubId: profile.id }); | ||
if (user) { | ||
user.name = profile.displayName; | ||
user.email = profile.emails?.[0]?.value; | ||
await user.save(); | ||
} else { | ||
user = await ( | ||
await User.create({ | ||
githubId: profile.id, | ||
name: profile.displayName, | ||
email: profile.emails?.[0]?.value, | ||
}) | ||
).save(); | ||
} | ||
|
||
cb(null, { | ||
accessToken: sign( | ||
{ userId: user.id }, | ||
process.env.ACCESS_TOKEN_SECRET!, | ||
{ | ||
expiresIn: "1y", | ||
} | ||
), | ||
}); | ||
} | ||
) | ||
); | ||
|
||
app.get("/auth/github", passport.authenticate("github", { session: false })); | ||
|
||
app.get( | ||
"/auth/github/callback", | ||
passport.authenticate("github", { session: false }), | ||
(req: any, res) => { | ||
res.redirect(`http://localhost:54321/auth/${req.user.accessToken}`); | ||
} | ||
); | ||
|
||
app.get("/me", async (req, res) => { | ||
const authHeader = req.headers.authorization; | ||
if (!authHeader) { | ||
res.send({ user: null }); | ||
return; | ||
} | ||
const token = authHeader.split(" ")[1]; | ||
if (!token) { | ||
res.send({ user: null }); | ||
return; | ||
} | ||
|
||
let userId = ""; | ||
|
||
try { | ||
const payload: any = verify(token, process.env.ACCESS_TOKEN_SECRET!); | ||
userId = payload.userId; | ||
} catch (err) { | ||
res.send({ user: null }); | ||
return; | ||
} | ||
|
||
if (!userId) { | ||
res.send({ user: null }); | ||
return; | ||
} | ||
const user = await User.aggregate([ | ||
{ $match: { _id: mongoose.Types.ObjectId(userId) } }, | ||
{ | ||
$lookup: { | ||
from: "boards", | ||
localField: "_id", | ||
foreignField: "creatorId", | ||
as: "boards", | ||
}, | ||
}, | ||
]); | ||
res.send({ user: user[0] }); | ||
}); | ||
|
||
app.use("/board", boardRoutes); | ||
app.use("/todo-list", todoListRoutes); | ||
|
||
// connect to database | ||
mongoose.connect(process.env.MONGO_URL!, { | ||
useNewUrlParser: true, | ||
useUnifiedTopology: true, | ||
}); | ||
|
||
mongoose.connection.once("open", () => | ||
console.log("connected To MongoDB", process.env) | ||
); | ||
|
||
// test url | ||
app.get("/", (_, res) => res.send("Hello Here")); | ||
app.listen(3002, () => console.log(`listening on port 3002`)); | ||
}; | ||
|
||
main(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { RequestHandler } from "express"; | ||
import { verify } from "jsonwebtoken"; | ||
|
||
export const isAuth: RequestHandler<{}, any, any, {}> = (req, _, next) => { | ||
const authHeader = req.headers.authorization; | ||
if (!authHeader) { | ||
throw new Error("Not Authenticated"); | ||
} | ||
const token = authHeader.split(" ")[1]; | ||
if (!token) { | ||
throw new Error("Not Authenticated"); | ||
} | ||
|
||
try { | ||
const payload: any = verify(token, process.env.ACCESS_TOKEN_SECRET!); | ||
(req as any).userId = payload.userId; | ||
next(); | ||
return; | ||
} catch {} | ||
|
||
throw new Error("Not Authenticated"); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import mongoose, { Schema } from "mongoose"; | ||
|
||
export interface IBoard extends mongoose.Document { | ||
name: string; | ||
creatorId: string; | ||
todoLists?: Array<string>; | ||
} | ||
|
||
const BoardSchema = new Schema({ | ||
creatorId: { type: Schema.Types.ObjectId }, | ||
name: { type: String }, | ||
todoLists: [ | ||
{ | ||
type: Schema.Types.ObjectId, | ||
}, | ||
], | ||
}); | ||
|
||
export default mongoose.model<IBoard>("Board", BoardSchema); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import mongoose, { Schema } from "mongoose"; | ||
|
||
export interface ITodoList extends mongoose.Document { | ||
boardId: string; | ||
creatorId: string; | ||
title: string; | ||
todos: Array<{ _id: string; todo: string }>; | ||
} | ||
|
||
export const Todo = new Schema({ | ||
_id: { type: String, require: true }, | ||
todo: { type: String, require: true }, | ||
}); | ||
|
||
const TodoListSchema = new Schema({ | ||
boardId: { type: Schema.Types.ObjectId }, | ||
creatorId: { type: Schema.Types.ObjectId }, | ||
title: { type: String, require: true }, | ||
todos: [Todo], | ||
}); | ||
|
||
export default mongoose.model<ITodoList>("TodoList", TodoListSchema); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import mongoose from "mongoose"; | ||
|
||
export interface IUser extends mongoose.Document { | ||
name?: string; | ||
email?: string; | ||
githubId?: string; | ||
} | ||
|
||
const UserSchema = new mongoose.Schema({ | ||
githubId: { type: String, unique: true }, | ||
name: { type: String }, | ||
email: { type: String }, | ||
}); | ||
|
||
export default mongoose.model<IUser>("User", UserSchema); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import express from "express"; | ||
|
||
import Board from "../models/Board"; | ||
import TodoList from "../models/TodoList"; | ||
|
||
import { isAuth } from "../middlewares/isAuth"; | ||
|
||
const routes = express.Router(); | ||
|
||
routes.post("/", isAuth, async (req: any, res) => { | ||
const board = await Board.create({ | ||
creatorId: req.userId, | ||
name: req.body.name, | ||
}); | ||
await board.save(); | ||
res.send({ board }); | ||
}); | ||
|
||
routes.delete("/", isAuth, async (req: any, res) => { | ||
const board = await Board.findById(req.body.id); | ||
if (board && board.creatorId.toString() === req.userId) { | ||
const promises = []; | ||
promises.push(Board.findByIdAndDelete(req.body.id)); | ||
promises.push(TodoList.deleteMany({ boardId: board._id })); | ||
await Promise.all(promises); | ||
return res.send({ success: true }); | ||
} | ||
return res.send({ success: false }); | ||
}); | ||
|
||
routes.put("/", isAuth, async (req: any, res) => { | ||
const board = await Board.findById(req.body._id); | ||
if (!board) { | ||
return res.send({ success: false }); | ||
} | ||
if (board.creatorId.toString() === req.userId) { | ||
if (req.body.name?.trim?.()) { | ||
board.name = req.body.name.trim(); | ||
} | ||
await board.save(); | ||
return res.send({ success: true, board }); | ||
} | ||
return res.send({ success: false }); | ||
}); | ||
|
||
export default routes; |
Oops, something went wrong.