Skip to content

Last modified: May 13, 2025

User Actions Part 2

demo/
├── routes/
│   └── api/
│       └── v1/
│           └── apiv1.js
│           └── controllers/
│               └─ users.js
├── public/
│   └── index.html
│   └── stylesheets/
│       └── style.css
│   └── javascripts/
│       └── index.js
├── models.js
└── app.js


app.js

import express from 'express';
import path from 'path';
import cookieParser from 'cookie-parser';
import logger from 'morgan';

import apiv1Router from './routes/api/v1/apiv1.js'

import models from './models.js'

import { fileURLToPath } from 'url';
import { dirname } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

var app = express();

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use((req, res, next) => {
    req.models = models
    next()
})

app.use('/api/v1', apiv1Router)

export default app;

models.js

import mongoose from "mongoose"

const models = {}

console.log("Trying to connect to mongodb")
await mongoose.connect("mongodb+srv://amelialx99:DgBDwhe7oQWZuKup@cluster0.i36zdqv.mongodb.net/playlists")

console.log("successfully connected to mongodb")

const userSchema = new mongoose.Schema({
    username: String,
    favorite_bands: [String]
})

models.User = mongoose.model("User", userSchema)

const playlistSchema = new mongoose.Schema({
    title: String,
    songs: String,
    user: {type: mongoose.Schema.Types.ObjectId, ref: "User"}
})

models.Playlist = mongoose.model("Playlist", playlistSchema)

console.log("successfully created database models")

export default models

apiv1.js

import express from 'express'
const router = express.Router()

import usersRouter from './controllers/users.js'
import playlistsRouter from './controllers/playlists.js'

router.use('/users', usersRouter)
router.use('/playlists', playlistsRouter)

export default router

users.js

import express from 'express'
const router = express.Router()

router.get('/', async (req, res) => {
    try{
        let allUsers = await req.models.User.find()
        res.json(allUsers)
    } catch(err){
        console.log("error", err)
        res.status(500).json({status: "server error"})
    }
})

router.post('/', async (req, res) => {
    try{
        const username = req.body.username
        let newUser = new req.models.User({
            username: username
        })

        await newUser.save()

        res.json({status: 'success'})
    } catch(err){
        console.log("error", err)
        res.status(500).json({status: "server error"})
    }
})

router.delete('/', async (req, res) => {
    let userId = req.body.userId

    // delete all playlists for the user, then the user itself
    await req.models.Playlist.deleteMany({user: userId})
    await req.models.User.deleteOne({_id: userId})

    res.send({status: "success"})
})

router.post('/bands', async (req, res) => {
    let userId = req.body.userId
    let band = req.body.band

    // find the right user
    let user = await req.models.User.findById(userId)

    // update with the new band (if it wasn't already there)
    if(!user.favorite_bands.includes(band)){
        user.favorite_bands.push(band)
    }

    // save
    await user.save()
    res.json({status: 'success'})
    // TODO: catch errors
})

export default router

index.html

<html>

<head>
  <title>Info upload</title>
  <link rel="stylesheet" href="/stylesheets/style.css">
  <script src="javascripts/index.js" ></script>
</head>

<body>
  <h1>Playlist</h1>
  <h2>Add User</h2>
  Name: <input id="name_input" type=text />
  <br>
  <button onclick = "addUser()">Add User</button>
  <div id="results"></div>

  <hr>
  <h2>All users</h2>
  <button onclick="loadUsers()">Load Users</button>
  <div id="allusersdiv">
    click "Load Users" to see users
  </div>

</body>

</html>

index.js

async function addUser(){
    let name = document.getElementById("name_input").value

    await fetch("/api/v1/users", {
        method: "POST",
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({username: name})
    })
}

async function loadUsers(){
    document.getElementById("allusersdiv").innerText = "loading..."

    let response = await fetch("/api/v1/users")
    let usersJson = await response.json()

    let usersHTML = usersJson.map(userInfo => {
        return `
        <hr>
        <div>
            <h3>
                Username: ${userInfo.username}
                <button onclick="deleteUser('${userInfo._id}')">Delete</button>
            </h3>
            <strong>Favorite Bands:</strong> ${userInfo.favorite_bands ? userInfo.favorite_bands.join(", ") : ""} <br>
            <strong>Add Band:</strong> <input type="text" id="add_band_text_${userInfo._id}" />
            <button onclick="addBand('${userInfo._id}')">Add Band</button>

            <h3>Playlists</h3>
            <div id="playlist_div_${userInfo._id}">Loading playlists...</div>

            <h3>Add Playlist</h3>
            <strong>Title:</strong> <input type="text" id="add_playlist_title_text_${userInfo._id}" /> <br>
            <strong>Songs:</strong> <input type="text" id="add_playlist_song_text_${userInfo._id}" /> <br>
            <button onclick="addPlaylist('${userInfo._id}')">Add Playlist</button>
        </div>
        `
    }).join("<hr>")

    document.getElementById("allusersdiv").innerHTML = usersHTML 

    usersJson.forEach(userInfo => {
        loadPlaylistsForUser(userInfo._id)
    })
}

async function loadPlaylistsForUser(userId){
    // get playlists for that user
    let response = await fetch("/api/v1/playlists?userId=" + userId)
    let playlistJSON = await response.json()

    // add html to the right div for that user
    let playlistHTML = playlistJSON.map(playalistInfo => {
        return `
        <div>
            <h4>Playlist: ${playalistInfo.title}</h4>
            <strong>Songs:</strong> ${playalistInfo.songs}
        </div>
        `
    }).join("")

    document.getElementById("playlist_div_" + userId).innerHTML = playlistHTML

}

async function addPlaylist(id){
    let title = document.getElementById("add_playlist_title_text_" + id).value
    let songs = document.getElementById("add_playlist_song_text_" + id).value

    await fetch("/api/v1/playlists", {
        method: "POST",
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
            title: title,
            songs: songs,
            userId: id
        })
    })

}

async function addBand(id){
    let bandToAdd = document.getElementById("add_band_text_" + id).value

    await fetch("/api/v1/users/bands", {
        method: "POST",
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
            userId: id,
            band: bandToAdd
        })
    })
}

async function deleteUser(id){
    await fetch("/api/v1/users", {
        method: "DELETE",
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
            userId: id
        })
    })
}