Skip to content

Commit

Permalink
bort soon
Browse files Browse the repository at this point in the history
  • Loading branch information
Ghcat0528 committed Jan 23, 2025
1 parent 00d45fc commit ec940c5
Show file tree
Hide file tree
Showing 10 changed files with 2,163 additions and 2 deletions.
1,839 changes: 1,839 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

13 changes: 11 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,17 @@
"description": "Introducing Jukebox Pro, the successor to Jukebox! Users will now need to make an account and log in before they are able to manage their playlists.",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "echo \"Error: no test specified\" && exit 1",
"seed": "node prisma/seed.js",
"dev": "nodemon server.js"
},
"author": "",
"license": "ISC"
"license": "ISC",
"dependencies": {
"@prisma/client": "^6.2.1",
"bcrypt": "^5.1.1",
"express": "^4.21.2",
"nodemon": "^3.1.9",
"prisma": "^6.2.1"
}
}
49 changes: 49 additions & 0 deletions prisma/migrations/20250123023655_init/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
-- CreateTable
CREATE TABLE "User" (
"id" SERIAL NOT NULL,
"username" TEXT NOT NULL,
"password" TEXT NOT NULL,

CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "Playlist" (
"id" SERIAL NOT NULL,
"name" TEXT NOT NULL,
"description" TEXT NOT NULL,
"ownerId" INTEGER NOT NULL,

CONSTRAINT "Playlist_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "Track" (
"id" SERIAL NOT NULL,
"name" TEXT NOT NULL,

CONSTRAINT "Track_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "_PlaylistTracks" (
"A" INTEGER NOT NULL,
"B" INTEGER NOT NULL,

CONSTRAINT "_PlaylistTracks_AB_pkey" PRIMARY KEY ("A","B")
);

-- CreateIndex
CREATE UNIQUE INDEX "User_username_key" ON "User"("username");

-- CreateIndex
CREATE INDEX "_PlaylistTracks_B_index" ON "_PlaylistTracks"("B");

-- AddForeignKey
ALTER TABLE "Playlist" ADD CONSTRAINT "Playlist_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "_PlaylistTracks" ADD CONSTRAINT "_PlaylistTracks_A_fkey" FOREIGN KEY ("A") REFERENCES "Playlist"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "_PlaylistTracks" ADD CONSTRAINT "_PlaylistTracks_B_fkey" FOREIGN KEY ("B") REFERENCES "Track"("id") ON DELETE CASCADE ON UPDATE CASCADE;
3 changes: 3 additions & 0 deletions prisma/migrations/migration_lock.toml
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 (e.g., Git)
provider = "postgresql"
36 changes: 36 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

// 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())
username String @unique
password String
playlists Playlist[]
}

model Playlist {
id Int @id @default(autoincrement())
name String
description String
owner User @relation(fields: [ownerId], references: [id])
ownerId Int
tracks Track[] @relation("PlaylistTracks")
}

model Track {
id Int @id @default(autoincrement())
name String
playlists Playlist[] @relation("PlaylistTracks")
}
42 changes: 42 additions & 0 deletions prisma/seed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();

async function seed() {
const tracks = [
{ name: "Track 1" },
{ name: "Track 2" },
{ name: "Track 3" },
{ name: "Track 4" },
{ name: "Track 5" },
{ name: "Track 6" },
{ name: "Track 7" },
{ name: "Track 8" },
{ name: "Track 9" },
{ name: "Track 10" },
{ name: "Track 11" },
{ name: "Track 12" },
{ name: "Track 13" },
{ name: "Track 14" },
{ name: "Track 15" },
{ name: "Track 16" },
{ name: "Track 17" },
{ name: "Track 18" },
{ name: "Track 19" },
{ name: "Track 20" },
];

await prisma.track.createMany({ data: tracks });

console.log("Tracks seeded successfully!");
}

seed()
.catch((e) => {
console.error("Error seeding database:", e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});

seed();
41 changes: 41 additions & 0 deletions routes/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const express = require('express');
const { PrismaClient } = require('@prisma/client');
const bcrypt = require("bcrypt");
const prisma = new PrismaClient();
const router = express.Router();




router.post('/register', async (req, res, next) => {
const { username, password } = req.body;
try {
const hashedPassword = await bcrypt.hash(password, 10);
const newUser = await prisma.user.create({
data: { username, password: hashedPassword },
});
res.status(201).json({ message: 'User created successfully!' });
} catch (error) {
next(error);
}
});

router.post('/login', async (req, res, next) => {
const { username, password } = req.body;
try {
const user = await prisma.user.findUnique({ where: { username } });
if (!user) {
return res.status(400).json({ error: 'Invalid credentials' });
}

const validPassword = await bcrypt.compare(password, user.password);
if (!validPassword) {
return res.status(400).json({ error: 'Invalid credentials' });
}

res.json({ message: 'Logged in successfully!' });
} catch (error) {
next(error);
}
});
module.exports= router;
66 changes: 66 additions & 0 deletions routes/playlists.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
const express = require("express");
const { PrismaClient } = require("@prisma/client");
const bcrypt = require("bcrypt");
const router = express.Router();
const prisma = new PrismaClient();

router.post("/", async (req, res) => {
const { username, password, name, description, trackIds } = req.body;

try {
const user = await prisma.user.findUnique({
where: { username },
});
if (!user) {
return res.status(401).json({ error: "Unauthorized: Nah" });
}
const isValid = await bcrypt.compare(password, user.password);
if (!isValid) {
return res.status(401).json({ error: "Unauthorized: WRONG" });
}
const validTracks = await prisma.track.findMany({
where: {
id: { in: trackIds },
},
});
if (validTracks.length !== trackIds.length) {
return res.status(400).json({
error: "One or more track IDs are invalid",
});
}
const newPlaylist = await prisma.playlist.create({
data: {
name,
description,
owner: { connect: { id: user.id } },
tracks: { connect: trackIds.map((id) => ({ id })) },
},
});

res.status(201).json(newPlaylist);
} catch (error) {
console.error(error);
res.status(500).json({ error: "Internal server error" });
}
});
router.get('/:id', async (req, res) => {
const playlistId = parseInt(req.params.id);

try {
const playlist = await prisma.playlist.findUnique({
where: { id: playlistId },
include: { tracks: true, owner: true },
});

if (!playlist) {
return res.status(404).json({ error: 'Playlist not found' });
}

res.json(playlist);
} catch (error) {
console.error('Error fetching playlist:', error);
res.status(500).json({ error: 'Internal server error' });
}
});

module.exports = router;
60 changes: 60 additions & 0 deletions routes/tracks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
const express = require("express");
const { PrismaClient } = require("@prisma/client");
const bcrypt = require("bcrypt");
const router = express.Router();
const prisma = new PrismaClient();

const validateUser = async (req, res, next) => {
const { username, password } = req.body;
try {
const user = await prisma.user.findUnique({ where: { username } });
if (!user) {
return res.status(400).json({ error: "Invalid credentials" });
}
req.user = user;
next();
} catch (error) {
next(error);
}
};
router.get("/", async (req, res) => {
try {
const tracks = await prisma.track.findMany({
include: {
playlists: true,
},
});

res.json(tracks);
} catch (error) {
console.error("Error fetching tracks:", error);
res.status(500).json({ error: "Internal server error" });
}
});

router.get("/:id", validateUser, async (req, res) => {
const trackId = parseInt(req.params.id);
try {
const track = await prisma.track.findUnique({
where: { id: trackId },
include: { playlists: true },
});

if (!track) {
return res.status(404).json({ error: "Track not found" });
}
if (req.user) {
const userPlaylists = track.playlists.filter(
(playlist) => playlist.ownerId === req.user.id
);
res.json({ track, userPlaylists });
} else {
res.json(track);
}
} catch (error) {
console.error("Error fetching track:", error);
res.status(500).json({ error: "Internal server error" });
}
});

module.exports = router;
16 changes: 16 additions & 0 deletions server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const express = require('express');
const bodyParser = require('body-parser');
const authRoutes = require('./routes/auth');
const playlistRoutes = require('./routes/playlists');
const trackRoutes = require('./routes/tracks');
const app = express();
const PORT = 3999

app.use(bodyParser.json());
app.use('/auth', authRoutes);
app.use('/playlists', playlistRoutes);
app.use('/tracks', trackRoutes);

app.listen(3999, () => {
console.log(`Server is running on port ${PORT}`);
});

0 comments on commit ec940c5

Please sign in to comment.