Riley Infrastructure - TheEvergreenStateCollege/upper-division-cs-23-24 GitHub Wiki

Back

Infrastructure


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 });
}

Screenshot 2024-06-12 154637


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;

Screenshot 2024-06-12 160324

Screenshot 2024-06-12 160344


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);

Screenshot 2024-06-12 165307


⚠️ **GitHub.com Fallback** ⚠️