Skip to content
Open
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
4 changes: 0 additions & 4 deletions .env.example

This file was deleted.

4 changes: 2 additions & 2 deletions requirements/03 - Movie - Client.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ Work inside the `handleCreateMovie` function in [src/client/App.jsx](../src/clie
The `title`, `description` and `runtimeMins` parameters of the function are already hooked up to the form so you can focus on the function logic.

1. Send a request to the `/movie` route to create a new movie using the parameters provided in the function.
1. You must add an appropriate auth header to the request
2. The value of the header must be the token obtained during login, which should be available in local storage
1. You must add an appropriate auth header to the request
2. The value of the header must be the token obtained during login, which should be available in local storage
2. Update the `movies` state to include the newly created movie. The list of movies must re-render without requiring a page refresh.
74 changes: 65 additions & 9 deletions src/client/App.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import './App.css';
import MovieForm from './components/MovieForm';
import UserForm from './components/UserForm';
import { useEffect, useState } from "react";
import "./App.css";
import MovieForm from "./components/MovieForm";
import UserForm from "./components/UserForm";

const port = import.meta.env.VITE_PORT;
const apiUrl = `http://localhost:${port}`;
Expand All @@ -11,8 +11,8 @@ function App() {

useEffect(() => {
fetch(`${apiUrl}/movie`)
.then(res => res.json())
.then(res => setMovies(res.data));
.then((res) => res.json())
.then((res) => setMovies(res.data));
}, []);

/**
Expand All @@ -34,16 +34,72 @@ function App() {
* */

const handleRegister = async ({ username, password }) => {
try {
const response = await fetch(`${apiUrl}/user/register`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ username, password }),
});

if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || "Something went wrong!");
}

const data = await response.json();
console.log("Registration successful:", data);
} catch (error) {
console.error("Error during registration:", error);
}
};

const handleLogin = async ({ username, password }) => {
try {
const response = await fetch(`${apiUrl}/user/login`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ username, password }),
});

if (!response.ok) {
throw new Error("Login failed");
}

const data = await response.json();
const token = data.token;

localStorage.setItem("authToken", token);

console.log("Login successful, token saved to local storage");
} catch (error) {
console.log("Login failed:", error);
}
};

const handleCreateMovie = async ({ title, description, runtimeMins }) => {

}
try {
const token = localStorage.getItem("token");
const res = await fetch(`${apiUrl}/movie`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `bearer ${token}`,
},
body: JSON.stringify({ title, description, runtimeMins }),
});
if (!res.ok) {
throw new Error("failed");
}
const data = await res.json();
console.log("Created Movie: ", data);
} catch (e) {
console.log("Error creating movie: ", e);
}
};

return (
<div className="App">
Expand All @@ -58,7 +114,7 @@ function App() {

<h1>Movie list</h1>
<ul>
{movies.map(movie => {
{movies.map((movie) => {
return (
<li key={movie.id}>
<h3>{movie.title}</h3>
Expand Down
44 changes: 24 additions & 20 deletions src/server/controllers/movie.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
import jwt from 'jsonwebtoken';
import { PrismaClient } from '@prisma/client'
import jwt from "jsonwebtoken";
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();

const jwtSecret = 'mysecret';
const jwtSecret = "mysecret";

const getAllMovies = async (req, res) => {
const movies = await prisma.movie.findMany();
const movies = await prisma.movie.findMany();

res.json({ data: movies });
res.json({ data: movies });
};

const createMovie = async (req, res) => {
const { title, description, runtimeMins } = req.body;
const { title, description, runtimeMins } = req.body;

try {
const token = null;
// todo verify the token
} catch (e) {
return res.status(401).json({ error: 'Invalid token provided.' })
}

const createdMovie = null;
try {
const token = req.headers.authorization.split("");
const decodedToken = jwt.verify(token, jwtSecret);

res.json({ data: createdMovie });
};

export {
getAllMovies,
createMovie
if (!decodedToken) {
throw new Error("Invalid key");
}
const createdMovie = await prisma.movie.create({
data: {
title: title,
description: description,
runtimeMins: runtimeMins,
},
});
res.status(201).json({ data: createdMovie });
} catch (e) {
return res.status(401).json({ error: "Invalid" });
}
};
export { getAllMovies, createMovie };
49 changes: 27 additions & 22 deletions src/server/controllers/user.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,44 @@
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import { PrismaClient } from '@prisma/client'
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();

const jwtSecret = 'mysecret';
const jwtSecret = "mysecret";

const register = async (req, res) => {
const { username, password } = req.body;
const { username, password } = req.body;

const createdUser = null;
const hashedPassword = await bcrypt.hash(password, 8);

res.json({ data: createdUser });
const user = await prisma.user.create({
data: {
username,
password: hashedPassword,
},
});
res.status(201).json({ user: { username: user.username } });
};

const login = async (req, res) => {
const { username, password } = req.body;
const { username, password } = req.body;

const foundUser = null;
const foundUser = await prisma.user.findUnique({
where: { username: username },
});

if (!foundUser) {
return res.status(401).json({ error: 'Invalid username or password.' });
}
if (!foundUser) {
return res.status(401).json({ error: "Invalid username or password." });
}

const passwordsMatch = false;
const passwordsMatch = await bcrypt.compare(password, foundUser.password);

if (!passwordsMatch) {
return res.status(401).json({ error: 'Invalid username or password.' });
}
if (!passwordsMatch) {
return res.status(401).json({ error: "Invalid username or password." });
}

const token = null;
const token = jwt.sign({ username: username });

res.json({ data: token });
res.json({ data: token });
};

export {
register,
login
};
export { register, login };