-
Notifications
You must be signed in to change notification settings - Fork 7
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
1e15e8b
commit 1092f63
Showing
192 changed files
with
4,087 additions
and
29,688 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
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 |
---|---|---|
@@ -1,100 +1,46 @@ | ||
{ | ||
"name": "express-typescript-starter", | ||
"version": "0.1.0", | ||
"description": "A starting point for Node.js express apps with TypeScript", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/Microsoft/TypeScript-Node-Starter" | ||
}, | ||
"author": "Bowden Kelly", | ||
"license": "MIT", | ||
"name": "chess-community-backend", | ||
"version": "1.0.0", | ||
"main": "dist/server.js", | ||
"scripts": { | ||
"build-sass": "sass src/public/css/main.scss dist/public/css/main.css", | ||
"build-ts": "tsc", | ||
"build": "npm run build-sass && npm run build-ts && npm run lint && npm run copy-static-assets", | ||
"copy-static-assets": "ts-node copyStaticAssets.ts", | ||
"debug": "npm run build && npm run watch-debug", | ||
"lint": "tsc --noEmit && eslint \"**/*.{js,ts}\" --quiet --fix", | ||
"serve-debug": "nodemon --inspect dist/server.js", | ||
"serve": "node dist/server.js", | ||
"start": "npm run serve", | ||
"test": "jest --forceExit --coverage --verbose", | ||
"watch-debug": "concurrently -k -p \"[{name}]\" -n \"Sass,TypeScript,Node\" -c \"yellow.bold,cyan.bold,green.bold\" \"npm run watch-sass\" \"npm run watch-ts\" \"npm run serve-debug\"", | ||
"watch-node": "nodemon dist/server.js", | ||
"watch-sass": "sass --watch src/public/css/main.scss dist/public/css/main.css", | ||
"watch-test": "npm run test -- --watchAll", | ||
"watch-ts": "tsc -w", | ||
"watch": "concurrently -k -p \"[{name}]\" -n \"Sass,TypeScript,Node\" -c \"yellow.bold,cyan.bold,green.bold\" \"npm run watch-sass\" \"npm run watch-ts\" \"npm run watch-node\"" | ||
"start": "node dist/server.js", | ||
"dev": "ts-node-dev --respawn --transpile-only src/server.ts", | ||
"build": "tsc", | ||
"prisma:generate": "prisma generate", | ||
"prisma:migrate": "prisma migrate deploy" | ||
}, | ||
"dependencies": { | ||
"async": "3.2.2", | ||
"bcrypt-nodejs": "0.0.3", | ||
"bluebird": "3.7.2", | ||
"body-parser": "1.19.0", | ||
"compression": "1.7.4", | ||
"connect-mongo": "4.4.0", | ||
"dotenv": "8.2.0", | ||
"errorhandler": "1.5.1", | ||
"express": "4.17.1", | ||
"express-flash": "0.0.2", | ||
"express-session": "1.17.1", | ||
"express-validator": "6.9.2", | ||
"fbgraph": "1.4.4", | ||
"lodash": "^4.17.21", | ||
"lusca": "1.6.1", | ||
"mongoose": "5.11.15", | ||
"nodemailer": "6.6.1", | ||
"passport": "0.4.1", | ||
"passport-facebook": "3.0.0", | ||
"passport-local": "1.0.0", | ||
"pug": "3.0.2", | ||
"winston": "3.3.3" | ||
"@prisma/client": "^3.15.2", | ||
"axios": "^0.27.2", | ||
"compression": "^1.7.4", | ||
"cors": "^2.8.5", | ||
"dotenv": "^16.4.5", | ||
"express": "^4.18.1", | ||
"express-session": "^1.18.0", | ||
"googleapis": "^140.0.0", | ||
"helmet": "^5.1.1", | ||
"joi": "^17.13.3", | ||
"jsonwebtoken": "^8.5.1", | ||
"node-cron": "^3.0.3", | ||
"passport": "^0.6.0", | ||
"passport-google-oauth20": "^2.0.0", | ||
"passport-jwt": "^4.0.1", | ||
"redis": "^4.6.14", | ||
"winston": "^3.8.1" | ||
}, | ||
"devDependencies": { | ||
"@types/async": "3.2.5", | ||
"@types/bcrypt-nodejs": "0.0.31", | ||
"@types/bluebird": "3.5.33", | ||
"@types/body-parser": "1.19.0", | ||
"@types/bson": "4.0.5", | ||
"@types/chai": "4.2.14", | ||
"@types/compression": "1.7.0", | ||
"@types/concurrently": "5.2.1", | ||
"@types/errorhandler": "1.5.0", | ||
"@types/eslint": "7.2.6", | ||
"@types/express": "4.17.11", | ||
"@types/express-flash": "0.0.2", | ||
"@types/express-session": "1.17.3", | ||
"@types/jest": "^26.0.23", | ||
"@types/jquery": "3.5.5", | ||
"@types/lodash": "^4.14.170", | ||
"@types/lusca": "1.6.2", | ||
"@types/mongodb": "3.6.5", | ||
"@types/node": "^14.18", | ||
"@types/nodemailer": "6.4.0", | ||
"@types/passport": "1.0.5", | ||
"@types/passport-facebook": "2.1.10", | ||
"@types/passport-local": "1.0.33", | ||
"@types/pug": "2.0.4", | ||
"@types/request": "2.48.5", | ||
"@types/request-promise": "4.1.47", | ||
"@types/shelljs": "0.8.8", | ||
"@types/supertest": "2.0.10", | ||
"@types/winston": "2.4.4", | ||
"@typescript-eslint/eslint-plugin": "4.14.2", | ||
"@typescript-eslint/parser": "4.14.2", | ||
"chai": "4.3.0", | ||
"concurrently": "6.0.2", | ||
"eslint": "7.19.0", | ||
"jest": "^27.0.6", | ||
"nodemon": "^2.0.7", | ||
"sass": "1.32.6", | ||
"shelljs": "0.8.5", | ||
"supertest": "6.1.3", | ||
"ts-jest": "^27.0.3", | ||
"ts-node": "9.1.1", | ||
"typescript": "4.1.3" | ||
}, | ||
"engines": { | ||
"node": ">=14.0.0" | ||
"@types/compression": "^1.7.2", | ||
"@types/cors": "^2.8.12", | ||
"@types/express": "^4.17.13", | ||
"@types/express-session": "^1.18.0", | ||
"@types/jsonwebtoken": "^8.5.8", | ||
"@types/node": "^18.0.0", | ||
"@types/node-cron": "^3.0.11", | ||
"@types/passport": "^1.0.9", | ||
"@types/passport-google-oauth20": "^2.0.11", | ||
"@types/passport-jwt": "^4.0.1", | ||
"prisma": "^3.15.2", | ||
"ts-node-dev": "^2.0.0", | ||
"typescript": "^4.7.4" | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
prisma/migrations/20240621221158_changeschema/migration.sql
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 @@ | ||
-- CreateTable | ||
CREATE TABLE "User" ( | ||
"id" TEXT NOT NULL, | ||
"googleId" TEXT NOT NULL, | ||
"email" TEXT NOT NULL, | ||
"name" TEXT NOT NULL, | ||
"chessUsername" TEXT, | ||
"youtubeChannelId" TEXT, | ||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
"updatedAt" TIMESTAMP(3) NOT NULL, | ||
|
||
CONSTRAINT "User_pkey" PRIMARY KEY ("id") | ||
); | ||
|
||
-- CreateIndex | ||
CREATE UNIQUE INDEX "User_googleId_key" ON "User"("googleId"); | ||
|
||
-- CreateIndex | ||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); | ||
|
||
-- CreateIndex | ||
CREATE UNIQUE INDEX "User_chessUsername_key" ON "User"("chessUsername"); |
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,17 @@ | ||
-- CreateTable | ||
CREATE TABLE "ChessInfo" ( | ||
"id" TEXT NOT NULL, | ||
"blitz" INTEGER NOT NULL, | ||
"bullet" INTEGER NOT NULL, | ||
"rapid" INTEGER NOT NULL, | ||
"puzzle" INTEGER NOT NULL, | ||
"userId" TEXT NOT NULL, | ||
|
||
CONSTRAINT "ChessInfo_pkey" PRIMARY KEY ("id") | ||
); | ||
|
||
-- CreateIndex | ||
CREATE UNIQUE INDEX "ChessInfo_userId_key" ON "ChessInfo"("userId"); | ||
|
||
-- AddForeignKey | ||
ALTER TABLE "ChessInfo" ADD CONSTRAINT "ChessInfo_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; |
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,3 @@ | ||
# Please do not edit this file manually | ||
# It should be added in your version-control system (i.e. Git) | ||
provider = "postgresql" |
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,31 @@ | ||
datasource db { | ||
provider = "postgresql" | ||
url = env("DATABASE_URL") | ||
} | ||
|
||
generator client { | ||
provider = "prisma-client-js" | ||
binaryTargets = ["native", "darwin-arm64"] | ||
} | ||
|
||
model User { | ||
id String @id @default(uuid()) | ||
googleId String @unique | ||
email String @unique | ||
name String | ||
chessUsername String? @unique | ||
youtubeChannelId String? | ||
createdAt DateTime @default(now()) | ||
updatedAt DateTime @updatedAt | ||
chessInfo ChessInfo? | ||
} | ||
|
||
model ChessInfo { | ||
id String @id @default(uuid()) | ||
blitz Int | ||
bullet Int | ||
rapid Int | ||
puzzle Int | ||
userId String @unique | ||
user User @relation(fields: [userId], references: [id]) | ||
} |
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 |
---|---|---|
@@ -1,118 +1,35 @@ | ||
import express from "express"; | ||
import compression from "compression"; // compresses requests | ||
import session from "express-session"; | ||
import bodyParser from "body-parser"; | ||
import lusca from "lusca"; | ||
import MongoStore from "connect-mongo"; | ||
import flash from "express-flash"; | ||
import path from "path"; | ||
import mongoose from "mongoose"; | ||
import passport from "passport"; | ||
import bluebird from "bluebird"; | ||
import { MONGODB_URI, SESSION_SECRET } from "./util/secrets"; | ||
import express from 'express'; | ||
import passport from 'passport'; | ||
import cors from 'cors'; | ||
import helmet from 'helmet'; | ||
import compression from 'compression'; | ||
import session from 'express-session'; | ||
import { errorHandler } from './middlewares/errorHandler'; | ||
import authRoutes from './routes/auth'; | ||
import './config/passport'; | ||
import './utils/scheduler'; | ||
|
||
// Controllers (route handlers) | ||
import * as homeController from "./controllers/home"; | ||
import * as userController from "./controllers/user"; | ||
import * as apiController from "./controllers/api"; | ||
import * as contactController from "./controllers/contact"; | ||
|
||
// API keys and Passport configuration | ||
import * as passportConfig from "./config/passport"; | ||
|
||
// Create Express server | ||
const app = express(); | ||
|
||
// Connect to MongoDB | ||
const mongoUrl = MONGODB_URI; | ||
mongoose.Promise = bluebird; | ||
|
||
mongoose.connect(mongoUrl, { useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true } ).then( | ||
() => { /** ready to use. The `mongoose.connect()` promise resolves to undefined. */ }, | ||
).catch(err => { | ||
console.log(`MongoDB connection error. Please make sure MongoDB is running. ${err}`); | ||
// process.exit(); | ||
}); | ||
|
||
// Express configuration | ||
app.set("port", process.env.PORT || 3000); | ||
app.set("views", path.join(__dirname, "../views")); | ||
app.set("view engine", "pug"); | ||
app.use(cors()); | ||
app.use(helmet()); | ||
app.use(compression()); | ||
app.use(bodyParser.json()); | ||
app.use(bodyParser.urlencoded({ extended: true })); | ||
app.use(express.json()); | ||
app.use(express.urlencoded({ extended: true })); | ||
|
||
// Configure express-session | ||
app.use(session({ | ||
resave: true, | ||
saveUninitialized: true, | ||
secret: SESSION_SECRET, | ||
store: new MongoStore({ | ||
mongoUrl, | ||
mongoOptions: { | ||
autoReconnect: true | ||
} | ||
}) | ||
secret: process.env.SESSION_SECRET || 'your_secret_key', // Use a strong secret key | ||
resave: false, | ||
saveUninitialized: false, | ||
cookie: { secure: process.env.NODE_ENV === 'production' } // Use secure cookies in production | ||
})); | ||
|
||
app.use(passport.initialize()); | ||
app.use(passport.session()); | ||
app.use(flash()); | ||
app.use(lusca.xframe("SAMEORIGIN")); | ||
app.use(lusca.xssProtection(true)); | ||
app.use((req, res, next) => { | ||
res.locals.user = req.user; | ||
next(); | ||
}); | ||
app.use((req, res, next) => { | ||
// After successful login, redirect back to the intended page | ||
if (!req.user && | ||
req.path !== "/login" && | ||
req.path !== "/signup" && | ||
!req.path.match(/^\/auth/) && | ||
!req.path.match(/\./)) { | ||
req.session.returnTo = req.path; | ||
} else if (req.user && | ||
req.path == "/account") { | ||
req.session.returnTo = req.path; | ||
} | ||
next(); | ||
}); | ||
|
||
app.use( | ||
express.static(path.join(__dirname, "public"), { maxAge: 31557600000 }) | ||
); | ||
|
||
/** | ||
* Primary app routes. | ||
*/ | ||
app.get("/", homeController.index); | ||
app.get("/login", userController.getLogin); | ||
app.post("/login", userController.postLogin); | ||
app.get("/logout", userController.logout); | ||
app.get("/forgot", userController.getForgot); | ||
app.post("/forgot", userController.postForgot); | ||
app.get("/reset/:token", userController.getReset); | ||
app.post("/reset/:token", userController.postReset); | ||
app.get("/signup", userController.getSignup); | ||
app.post("/signup", userController.postSignup); | ||
app.get("/contact", contactController.getContact); | ||
app.post("/contact", contactController.postContact); | ||
app.get("/account", passportConfig.isAuthenticated, userController.getAccount); | ||
app.post("/account/profile", passportConfig.isAuthenticated, userController.postUpdateProfile); | ||
app.post("/account/password", passportConfig.isAuthenticated, userController.postUpdatePassword); | ||
app.post("/account/delete", passportConfig.isAuthenticated, userController.postDeleteAccount); | ||
app.get("/account/unlink/:provider", passportConfig.isAuthenticated, userController.getOauthUnlink); | ||
|
||
/** | ||
* API examples routes. | ||
*/ | ||
app.get("/api", apiController.getApi); | ||
app.get("/api/facebook", passportConfig.isAuthenticated, passportConfig.isAuthorized, apiController.getFacebook); | ||
app.use('/api/auth', authRoutes); | ||
|
||
/** | ||
* OAuth authentication routes. (Sign in) | ||
*/ | ||
app.get("/auth/facebook", passport.authenticate("facebook", { scope: ["email", "public_profile"] })); | ||
app.get("/auth/facebook/callback", passport.authenticate("facebook", { failureRedirect: "/login" }), (req, res) => { | ||
res.redirect(req.session.returnTo || "/"); | ||
}); | ||
app.use(errorHandler); | ||
|
||
export default app; | ||
export default app; |
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,17 @@ | ||
import axios from 'axios'; | ||
|
||
export const chessComConfig = { | ||
baseURL: 'https://api.chess.com/pub/player', | ||
headers: { | ||
'User-Agent': 'chessconnect ([email protected])', | ||
}, | ||
}; | ||
|
||
export const isValidChessComId = async (chesscomId: string): Promise<boolean> => { | ||
try { | ||
const response = await axios.get(`${chessComConfig.baseURL}/${chesscomId}`, { headers: chessComConfig.headers }); | ||
return response.status === 200; | ||
} catch (error) { | ||
return false; | ||
} | ||
}; |
Oops, something went wrong.