Riley Infrastructure - TheEvergreenStateCollege/upper-division-cs-23-24 GitHub Wiki
HW-3 ✔️
So coming back to this way later, I was able to implement my prisma schema into my final project, specifically to my project and my goals with it. It saves a user model like the username and password, as well as a word model that is used in the user model. This is because I want each user to have a list of favorite words they have. I followed along the tutorial and was able to create typescript handlers for both my words model, as well as the user model. I was having issues getting these actually working, but a couple months back Paul, Duc, Torsten and I were able to get it working(ish) in an 4 hour discord call!// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
username String @unique
password String
Word Word[]
}
model Word {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
name String @db.VarChar(255)
define String
language String
authorId Int
User User @relation(fields: [authorId], references: [id])
}
import { Router } from "express";
import { body, validationResult } from "express-validator"
import { createWord, deleteWord, getOneWord, getWords } from './handlers/words';
import { getAllUsers } from './handlers/users';
import { create } from "domain";
const path = require('path');
const router = Router();
const wordValidators = [
body('name').isString(),
body('define').isString(),
body('language').isString(),
body('authorId').isNumeric(),
]
const deleteValidator = [
body('id').isNumeric()
]
router.get('/word', getWords);
router.get('/word/:name', getOneWord);
router.post('/word', ...wordValidators,
createWord
);
router.delete('/word', ...deleteValidator,
deleteWord
);
export default router;
import prisma from "../db";
import { Word } from '@prisma/client';
import { Request, Response } from 'express';
import { validationResult } from "express-validator";
export const getOneWord = async ( req: Request, res: Response ) => {
const word = await prisma.word.findFirst({
where: {
authorId: Number(req.user!.id)
}
});
res.json({ data: word });
}
export const getWords = async ( req: Request, res: Response ) => {
const allWords = await prisma.word.findMany({
where: {
authorId: Number(req.user!.id)
}
});
res.json({ data: allWords });
}
export const deleteWord = async ( req: Request, res: Response ) => {
const deleted = await prisma.word.delete({
where: {
id:Number(req.user!.id)
}
});
res.json({ data: deleteWord });
}
export const createWord = async ( req: Request, res: Response ) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
res.statusCode = 400;
res.json({ errors: errors.array() });
}
const word = await prisma.word.create({
data: {
name: req.body.name,
define: req.body.define,
language: req.body.language,
authorId: Number(req.user!.id),
}
});
res.json({ data: word });
}
HW-6 ✔️
I am coming back to this and was able to follow along all of both the authentication and route and error handling tutorials. I adapted the code to be compatible with my final project, since my project is based on random words I wanted users to be able to save random words that were their favorites. It also saves the language of the words, since in theory I would like to adapt this project to also generate random words in other languages. This is a feature I have not yet added. Overall I still find this pretty confusing, it’s a lot of working parts and I feel like we didn’t cover it at the depth that was required during last quarter.import { User } from '@prisma/client'
import { Response, NextFunction } from 'express'
import { Request } from '../types/express'
import jwt from 'jsonwebtoken'
import bcrypt from 'bcrypt'
export const comparePasswords = (password: string, hash: string) => {
return bcrypt.compare(password, hash)
}
export const hashPassword = (password: string) => {
return bcrypt.hash(password, 5)
}
export const createJWT = (user: User) => {
const token = jwt.sign({
id: user.id,
username: user.username
},
process.env.JWT_SECRET!
);
return token;
}
export const protect = (req: Request, res: Response, next: NextFunction) => {
const bearer = req.headers.authorization;
if (!bearer) {
res.status(401);
res.json({ message: 'not authorized' });
return;
}
const [, token] = bearer.split(' ');
if (!token) {
res.status(401);
res.json({ message: 'not valid token' });
return;
}
try {
// add payload from Paul's auth.ts
const user = jwt.verify(token, process.env.JWT_SECRET!)
//req.user = user
next()
} catch (e) {
console.error(e)
res.status(401)
res.json({message: 'not valid token'})
return
}
}
import express, { Request, Response, NextFunction } from 'express';
import router from './router'
import morgan from 'morgan'
import cors from 'cors'
import { protect } from './modules/auth';
import { createNewUser, signin } from './handlers/users'
import * as path from 'path';
const app = express()
app.use(cors())
app.use(morgan('dev'))
app.use(express.static("pages"));
app.use(express.json());
app.use(express.urlencoded({extended: true}));
app.get('/', async (req: Request, res: Response, next: NextFunction) => {
res.sendFile(path.resolve("pages/index.html"));
});
app.use('/api', protect, router);
app.use(async (err: any, req: Request, res: Response, next: NextFunction) => {
console.log(err);
res.json({message: `had an error: ${err.message}`});
});
app.use((err:any, req: Request, res: Response, next: NextFunction) => {
if (err.type == 'auth') {
res.status(401).json({message: 'unauthorized'})
} else if (err.type === 'input') {
res.status(400).json({message: 'invalid input'})
} else {
res.status(500).json({message: 'oops, thats on us'})
}
})
app.post('/signup', createNewUser);
app.post('/signin', signin);
export default app
import { Router } from "express";
import { body, validationResult } from "express-validator"
import { createWord, deleteWord, getOneWord, getWords } from './handlers/words';
import { getAllUsers } from './handlers/users';
import { create } from "domain";
const path = require('path');
const router = Router();
const wordValidators = [
body('name').isString(),
body('define').isString(),
body('language').isString(),
body('authorId').isNumeric(),
]
const deleteValidator = [
body('id').isNumeric()
]
router.get('/word', getWords);
router.get('/word/:name', getOneWord);
router.post('/word', ...wordValidators,
createWord
);
router.delete('/word', ...deleteValidator,
deleteWord
);
export default router;
HW-8 ✔️
I completed the tutorial on creating environment configurations and creating and running tests with jest. Overall I think I am still very confused on how to implement both of these things into my final project. There are a lot of moving parts and I am still confused on how everything works together. I do not have the time to create jest tests for my final project, but I am wondering how I would implement that. We only go over how to test to post to User, I am unsure how I would implement that for my word model. Oh well.
import app from "../server";
import request from "supertest";
describe("POST /user", function () {
it("responds with json", async () {
const res = await request(app)
.post("/user")
.send({ username: "hello", password: "hola" })
.set("Accept", "application/json")
expect(res.headers["Content-Type"]).toMatch(/json/);
expect(res.status).toEqual(200);
});
});
import app from "../server";
import request from "supertest";
describe("GET /", function () {
it("should send back some data", async () => {
const res = await supertest(app)
.get('/')
expect(res.body.message).toBe('hello')
})
})
import merge from "lodash.merge";
// make sure NODE_ENV is set
process.env.NODE_ENV = process.env.NODE_ENV || "development";
const stage = process.env.STAGE || "local";
let envConfig;
// dynamically require each config depending on the stage we're in
if (stage === "production") {
envConfig = require("./prod").default;
} else if (stage === "staging") {
envConfig = require("./staging").default;
} else {
envConfig = require("./local").default;
}
const defaultConfig = {
stage,
dbUrl: process.env.DATABASE_URL,
jwtSecret: process.env.JWT_SECRET,
port: process.env.PORT,
logging: false,
};
export default merge(defaultConfig, envConfig);