Chapter X

Milestones

Class Project Milestones!

Subsections of Milestones

Express Starter Project

This set of milestones is all about building a RESTful API and interface for the Lost Kansas Communities project.

Milestone 1 - Express Starter Project

Follow the instructions in the Example Project to build a project using Node.js and Express that includes the following features:

  1. A working GitHub Codespace containing Node.js
  2. A bare-bones Express application
  3. Update the Express application from CommonJS to ES Modules
  4. Application logs with Winston and Morgan
  5. Install other useful Express libraries like compression and helmet
  6. Install and configure Nodemon
  7. Install and configure dotenvx
  8. Create code documentation with JSDoc and OpenAPI comments
  9. Enable linting and formatting with ESLint and Prettier

Effectively, just follow along with the example project and submit the resulting repository. This will be the starting point for the rest of the milestones!

Add a Database

This set of milestones is all about building a RESTful API and interface for the Lost Kansas Communities project.

Milestone 2 - Add a Database

Building from the previous milestone, expand upon the starter project by adding the following features:

  1. Create an SQLite database
  2. Install and configure the Sequelize ORM and the Umzug migration tool
  3. Configure an automated process to migrate and seed the data on application startup
  4. Create database migrations, seeds, and models matching the database diagram given below

Database Diagram

Database Diagram Database Diagram

Seed Data

Seed data is stored in CSV files that can be downloaded from Canvas. See Seeding from a CSV File for an example of how to read data from a CSV file when seeding the database.

RESTful API

This set of milestones is all about building a RESTful API and interface for the Lost Kansas Communities project.

Milestone 3 - RESTful API

Building from the previous milestone, expand upon the starter project by adding the following features:

  1. Build a full RESTful API to manage the communities, counties, metadata, and documents. The RESTful API should faithfully implement the Open API specification given below.
    1. Notice that the /api/v1/documents/{id}/upload API path handles file uploads! We haven’t covered that in these examples, but there are some prior examples in this class to build upon.
    2. Pay special attention to the example inputs and outputs for each route. Your JSON should exactly match the structure of those examples. Note that some fields may be hidden in associated objects that are included.
  2. Each API endpoint should include full unit tests, with an explicit goal to test both successful and unsuccessful operations performed by that endpoint.
  3. All functions, files, and exported objects should be documented using JSDoc and Open API following the examples given.

Database Diagram

Database Diagram Database Diagram

Open API Specification

Tip

You can download this specification file by clicking the link below, and then edit the servers section to test it using your server. You can use the Open API Editor to see a cleaner view of this JSON file.

The OpenAPI specification looks best using the light theme. You can adjust the textbook theme in the left sidebar at the bottom of the textbook page.

Authentication

This set of milestones is all about building a RESTful API and interface for the Lost Kansas Communities project.

Milestone 4 - Authentication

Building from the previous milestone, expand upon the starter project by adding the following features:

  1. Implement Bypass authentication using the Unique Token Strategy in Passport.js as shown in the tutorial. When enabled via the .env file, it should allow authentication via the /auth/bypass?token=<username> route.
  2. Allow the system to create new users if a user tries to authenticate with a username not currently in the database. That user should not be assigned any roles by default.
  3. Implement CAS authentication strategy in Passport.js as shown in the tutorial. Users should be able to authenticate via the https://testcas.cs.ksu.edu server. CAS settings should be controlled via the .env file.
  4. Implement JSON Web Tokens via the /auth/token route as shown in the tutorial. The token should include the user’s ID and a list of roles assigned to the user.
  5. Require a valid JWT to access ALL routes under the /api/v1 path.
  6. Implement role-based authorization for ALL routes under the /api/v1 path. See below for a matrix of roles and allowed actions.
  7. Update unit tests for each route to use authentication and also to test role-based authorization as shown in the tutorial.
  8. Update the appropriate routes for both Communities and Metadata so that the owner_user_id foreign key is automatically set to the currently authenticated user (it should no longer be provided as part of the POST request to create a new community or metadata, nor should it be editable via PUT request.)
  9. Update the OpenAPI documentation and unit tests to match the change to Communities and Metadata above.

Authorization Matrix

  • Path: /api/v1/users
    • ALL ACTIONS: manage_users
  • Path: /api/v1/roles
    • GET: manage_users
  • Path: /api/v1/communities
    • GET: [view_communities, manage_communities, add_communities]
    • POST: [manage_communities, add_communities]
    • PUT: [manage_communities]
    • DELETE: [manage_communities]
  • Path: /api/v1/counties
    • GET: [view_communities, manage_communities, add_communities]
  • Path: /api/v1/documents
    • GET: [view_documents, manage_documents, add_documents]
    • POST: [manage_documents, add_documents] (including file uploads)
    • PUT: [manage_documents]
    • DELETE: [manage_documents]
  • Path: /api/v1/metadata
    • GET: [view_documents, manage_documents, add_documents]
    • POST: [manage_documents, add_documents] (including adding and removing communities and documents to metadata)
    • PUT: [manage_documents]
    • DELETE: [manage_documents]

Database Diagram

Database Diagram Database Diagram

Open API Specification

UPDATED FOR MILESTONE 4

Tip

You can download this specification file by clicking the link below, and then edit the servers section to test it using your server. You can use the Open API Editor to see a cleaner view of this JSON file.

The OpenAPI specification looks best using the light theme. You can adjust the textbook theme in the left sidebar at the bottom of the textbook page.

Vue.js Starter Project

This set of milestones is all about building a RESTful API and interface for the Lost Kansas Communities project.

Milestone 5 - Vue Starter Project

Follow the instructions in the Example Project to build a project using Vue.js that includes the following features:

  1. A single page frontend application running in Vue 3.
  2. Built-in Vue features such as Vue Router and Pinia.
  3. Access to components and icons from PrimeVue.
  4. Access to Tailwind CSS for additional CSS styling and features.
  5. A working Dark Mode Theme completed with a selector that remembers our preference.
  6. A working Vite server that will proxy requests to our backend RESTful API seamlessly.
  7. An Axios client that can access our RESTful API routes.
  8. A seamless system for authentication and requesting a JWT to access protected API routes.
  9. A demo of accessing the API on the /profile page listing all users and roles assigned to those users (this page should load correctly for the admin user)

Effectively, just follow along with the example project and submit the resulting repository. This will be the starting point for the rest of the milestones!

Vue.js CRUD App

This set of milestones is all about building a RESTful API and interface for the Lost Kansas Communities project.

Milestone 6 - Vue.js CRUD App

Building from the previous milestone, expand upon the starter project by adding the following features:

  1. Most menu items and routes are protected and only allow users with specific roles to view/access them
  2. A page that lists all roles in the application for anyone with the manage_users role. Roles are not editable.
  3. A page that lists all users in a data table for anyone with the manage_users role.
    1. Helpful columns on that page should be searchable and sortable, as well as the ability to filter by role.
    2. A page to edit existing users, including updating their roles.
    3. A page to create new users and assign new roles.
    4. A method to delete existing users.
  4. A page that lists all counties in the application for anyone with the view_communities, manage_communities and add_communities roles. Counties are not editable.
  5. A page that lists all communities in a data table for anyone with the view_communities, manage_communities and add_communities roles.
    1. Helpful columns on that page should be searchable and sortable.
    2. A page to edit existing communities, including changing the county that they are in, for anyone with the manage_communities role.
    3. A page to create new communities and associated with a county, for anyone with the manage_communities and add_communities roles.
    4. A method to delete existing communities, for anyone with the manage_communities role.
    5. For this milestone, you may hard-code the frontend to have all new communities owned by user ID 1 admin
  6. A page that lists all documents in a data table for anyone with the view_documents, manage_documents and add_documents roles.
    1. Helpful columns on that page should be searchable and sortable. Document filenames should be clickable, and it should direct users to the appropriate file on the server (if such file exists; this should work for all uploaded files)
    2. A page to edit existing documents, for anyone with the manage_documents role.
    3. A page to create new documents, for anyone with the manage_documents and add_documents roles.
    4. A method to delete existing documents, for anyone with the manage_documents role.
    5. When creating or editing a document, users should also have the ability to upload a new file for that document.

We will NOT be handling the interface for metadata in this milestone. That will be the last milestone for this project.

Hints

Clickable Filenames

To make filenames clickable, you’ll need to add an additional proxy route to the client/vite.config.js to allow users to access the uploads folder (or wherever you are storing your uploaded files). You can continue to use the Express static file middleware to serve these files.

File Uploads

To simplify the file upload process, you may want to ensure that files are named with the appropriate file extensions to match their mimetypes on the server. Below is an example if you are using multer to handle file uploads - it uses nanoid to generate random filenames and mime-types to get the correct file extension to match the mimetype of the file. You can then store the filename, size, and mimetype you get from multer in your endpoint for uploading files.

// Initialize Multer
const storage = multer.diskStorage({
  destination: "public/uploads",
  filename: function (req, file, cb) {
    cb(null, nanoid() + "." + mime.extension(file.mimetype));
  },
});
const upload = multer({ storage: storage });

On the frontend, you can use the PrimeVue FileUpload component to select the file, but you should implement a Custom Upload handler.

A brief but incomplete example is given below:

<script setup>
// Import Libraries
import { ref } from 'vue'
import { api } from '@/configs/api'
import { FileUpload, Button } from 'primevue'

// Declare State
const file = ref()

// Upload function - could possibly call this after saving the document but before redirecting
const upload = function (documentid) {
  // If the user has selected a file
  if (file.value.hasFiles) {
    // Fetch the file from the user's filesystem into the browser
    fetch(file.value.files[0].objectURL)
      // convert the file to a blob
      .then((response) => response.blob())
      .then((blob) => {
        // Create a file from the blob and add it to a form data object
        const fileUpload = new File([blob], file.value.files[0].name, { type: blob.type })
        const form = new FormData()
        form.append('file', fileUpload)
        // Upload that form to the endpoint
        api
          .post('/api/v1/documents/' + documentid + '/upload', form, {
            headers: {
              'Content-Type': 'multipart/form-data',
            },
          })
          .then(function (response) {
            // handle success
          })
          .catch(function (error) {
            // handle error uploading file
          })
      })
      .catch(function (error) {
        // handle error reading file
      })
  } else {
    // No file was selected
  }
}
</script>
  <FileUpload ref="file" mode="basic" name="file" customUpload />
  <Button severity="success" @click="upload(props.id)" label="Upload" />
<template>

Vue.js Components

This set of milestones is all about building a RESTful API and interface for the Lost Kansas Communities project.

Milestone 6 - Vue.js CRUD App

Building from the previous milestone, expand upon the starter project by adding the following features:

  1. Metadata view

  2. Fix bugs

  • Files are not protected - write custom handler to only allow access to uploaded files if permission allows
  • Communities & Metadata overly secure - allow owner to edit communities and/or metadata even if not have role
  • Update endpoint for creating communities and metadata to assign owner automatically
  • Properly handle deleting uploaded files when document is deleted; also delete uploaded files when overwritten