Lambda-School-Labs/Labs26-StorySquad-BE-TeamB

View on GitHub
api/submission/submissionRouter.js

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
const router = require('express').Router();

const { authRequired, fileUpload } = require('../middleware');
const { crudOperationsManager } = require('../../lib');

const Submissions = require('./submissionModel');

/**
 * Schemas for submission data types.
 * @swagger
 * components:
 *  schemas:
 *    SubmissionStatus:
 *      type: object
 *      properties:
 *        ID:
 *          type: integer
 *        ChildID:
 *          type: integer
 *        StoryID:
 *          type: integer
 *        CohortID:
 *          type: integer
 *        HasRead:
 *          type: boolean
 *        HasWritten:
 *          type: boolean
 *        HasDrawn:
 *          type: boolean
 *        Complexity:
 *          type: integer
 *        LowConfidence:
 *          type: boolean
 *        Status:
 *          type: string
 *          enum:
 *            - CLEAR
 *            - PENDING
 *            - ACCEPTED
 *            - REJECTED
 *      example:
 *        ID: 1
 *        ChildID: 1
 *        StoryID: 1
 *        CohortID: 1
 *        HasRead: false
 *        HasWritten: false
 *        HasDrawn: false
 *        Complexity: null
 *        Status: PENDING
 *    DrawnSubmission:
 *      type: object
 *      properties:
 *        URL:
 *          type: string
 *        checksum:
 *          type: string
 *      example:
 *        URL: http://someurl.com
 *        checksum: '25ef9314704f5f68b7e04513c1ca13c9146328ee14a38e1d7c99789ab11fae31e1c0238425d58581b3ac4941884cd389b7bea3f8e658f533adc7cf934bb130f8'
 *
 *    WrittenSubmission:
 *      allOf:
 *        - $ref: '#/components/schemas/DrawnSubmission'
 *        - type: object
 *          properties:
 *            PageNum:
 *              type: integer
 *          example:
 *            PageNum: 1
 *    GetDrawnSubmission:
 *      type: object
 *      properties:
 *        ID:
 *          type: integer
 *        URL:
 *          type: string
 *        SubmissionID:
 *          type: integer
 *      example:
 *        ID: 1
 *        URL: 'http://someurl.com'
 *        SubmissionID: 1
 *    GetWrittenSubmission:
 *      allOf:
 *        - $ref: '#/components/schemas/GetDrawnSubmission'
 *        - type: object
 *          properties:
 *            PageNum:
 *              type: integer
 *          example:
 *            PageNum: 1
 *    FullSubmission:
 *      type: object
 *      properties:
 *        ID:
 *          type: integer
 *        ChildId:
 *          type: integer
 *        StoryId:
 *          type: integer
 *        CohortId:
 *          type: integer
 *        HasRead:
 *          type: boolean
 *        HasWritten:
 *          type: boolean
 *        HasDrawn:
 *          type: boolean
 *        Complexity:
 *          type: integer
 *        pages:
 *          type: array
 *          items:
 *            $ref: '#/components/schemas/GetWrittenSubmission'
 *        image:
 *          $ref: '#/components/schemas/GetDrawnSubmission'
 *
 *  parameters:
 *    submissionId:
 *      name: Submission ID
 *      in: path
 *      description: ID of the desired submission
 *      required: true
 *      example: 1
 *      schema:
 *        type: integer
 */

/**
 * @swagger
 * /submission?childId={childId}&storyId={storyId}:
 *  get:
 *    summary: Queries the database for information for the given submission.
 *    description: Attempts to query the database to find a submission entry at the intersection
 *      of the given Child ID and Story ID. If none is found, one will be created and initialized
 *      with all false/null values.
 *    security:
 *      - okta: []
 *    tags:
 *      - Submissions
 *    parameters:
 *      - in: query
 *        name: childId
 *        schema:
 *          type: integer
 *        required: true
 *        description: numeric ID of child
 *      - in: query
 *        name: storyId
 *        schema:
 *          type: integer
 *        required: true
 *        description: numeric ID of story
 *    responses:
 *      200:
 *        description: Returns an object containing the data for the requested submission
 *        content:
 *          application/json:
 *            schema:
 *              $ref: '#/components/schemas/SubmissionStatus'
 *      400:
 *        $ref: '#/components/responses/MissingParameters'
 *      401:
 *        $ref: '#/components/responses/UnauthorizedError'
 *      404:
 *        $ref: '#/components/responses/InvalidID'
 *      500:
 *        $ref: '#/components/responses/DatabaseError'
 */
router.get('/', authRequired, async (req, res) => {
  // Pull intersection IDs out of the URL querystring
  const { childId, storyId } = req.query;

  crudOperationsManager.getAll(
    res,
    Submissions.getOrInitSubmission,
    'Submission',
    childId,
    storyId
  );
});

/**
 * @swagger
 * /submissions/child/{id}:
 *  get:
 *    summary: Attempts to get all data for every submission by a given child
 *    security:
 *      - okta: []
 *    tags:
 *      - Submissions
 *    parameters:
 *      - $ref: '#/components/parameters/childId'
 *    responses:
 *      200:
 *        description: Returns an array of all submissions by a child
 *        content:
 *          application/json:
 *            schema:
 *              type: array
 *              items:
 *                $ref: '#/components/schemas/FullSubmission'
 *      401:
 *        $ref: '#/components/responses/UnauthorizedError'
 *      500:
 *        $ref: '#/components/responses/DatabaseError'
 */
router.get('/child/:id', authRequired, async (req, res) => {
  // Pull child ID out of URL parameter
  const { id } = req.params;

  crudOperationsManager.getAll(res, Submissions.getAllSubmissionsByChild, 'Submission', id);
});

/**
 * @swagger
 * /submit/read/{id}:
 *  put:
 *    summary: Attempts to mark the submission with the given ID as 'read'
 *    security:
 *      - okta: []
 *    tags:
 *      - Submissions
 *    parameters:
 *      - $ref: '#/components/parameters/submissionId'
 *    responses:
 *      204:
 *        $ref: '#/components/responses/EmptySuccess'
 *      401:
 *        $ref: '#/components/responses/UnauthorizedError'
 *      404:
 *        $ref: '#/components/responses/NotFound'
 *      500:
 *        $ref: '#/components/responses/DatabaseError'
 */
router.put('/read/:id', authRequired, async (req, res) => {
  // Pull submission ID out of URL parameter
  const { id } = req.params;

  crudOperationsManager.update(res, Submissions.markAsRead, 'Submission', id);
});

/**
 * @swagger
 * /submit/write/{id}:
 *  post:
 *    summary: Attempts to upload pages for the submission with the given ID
 *    security:
 *      - okta: []
 *    tags:
 *      - Submissions
 *    parameters:
 *      - $ref: '#/components/parameters/submissionId'
 *      - in: formData
 *        name: pages
 *        type: file
 *        description: Image of the written page(s) to upload
 *    responses:
 *      201:
 *        description: Returns an array of all uploaded pages.
 *        content:
 *          application/json:
 *            schema:
 *              type: array
 *              items:
 *                $ref: '#/components/schemas/WrittenSubmission'
 *      401:
 *        $ref: '#/components/responses/UnauthorizedError'
 *      403:
 *        $ref: '#/components/responses/DuplicateError'
 *      404:
 *        $ref: '#/components/responses/NotFound'
 *      409:
 *        $ref: '#/components/responses/UploadFailed'
 *      500:
 *        $ref: '#/components/responses/DatabaseError'
 */
router.post('/write/:id', authRequired, fileUpload, async (req, res) => {
  // Pull relevant data out of the request object
  const { id } = req.params;
  const storyId = req.body.storyId;
  const pages = req.body.pages;

  // Callback function to pass into map that formats the data properly
  const cb = (x, i) => ({
    URL: x.Location,
    PageNum: i + 1,
    SubmissionID: id,
    checksum: x.Checksum,
  });

  crudOperationsManager.submission(
    res,
    Submissions.submitWritingTransaction,
    'Submission',
    pages,
    cb,
    id,
    storyId
  );
});

/**
 * @swagger
 * /submit/draw/{id}:
 *  post:
 *    summary: Attempts to upload a drawing for the submission with the given ID
 *    security:
 *      - okta: []
 *    tags:
 *      - Submissions
 *    parameters:
 *      - $ref: '#/components/parameters/submissionId'
 *      - in: formData
 *        name: drawing
 *        type: file
 *        description: Image of the drawing to upload
 *    responses:
 *      201:
 *        description: Returns the newly uploaded drawing.
 *        content:
 *          application/json:
 *            schema:
 *              type: array
 *              items:
 *                $ref: '#/components/schemas/DrawnSubmission'
 *      401:
 *        $ref: '#/components/responses/UnauthorizedError'
 *      403:
 *        $ref: '#/components/responses/DuplicateError'
 *      404:
 *        $ref: '#/components/responses/NotFound'
 *      409:
 *        $ref: '#/components/responses/UploadFailed'
 *      500:
 *        $ref: '#/components/responses/DatabaseError'
 */
router.post('/draw/:id', authRequired, fileUpload, async (req, res) => {
  // Pull relevant data out of the request object
  const { id } = req.params;
  const data = req.body.drawing;

  // Callback function to pass into map that formats the data properly
  const cb = (x) => ({
    URL: x.Location,
    SubmissionID: id,
    checksum: x.Checksum,
  });

  crudOperationsManager.submission(
    res,
    Submissions.submitDrawingTransaction,
    'Submission',
    data,
    cb,
    id
  );
});

/**
 * @swagger
 * /submission/write/{id}:
 *  delete:
 *    summary: Attempts to delete the writing submission with the specified submission ID.
 *    security:
 *      - okta: []
 *    tags:
 *      - Submissions
 *    parameters:
 *      - $ref: '#/components/parameters/submissionId'
 *    responses:
 *      204:
 *        $ref: '#/components/responses/EmptySuccess'
 *      401:
 *        $ref: '#/components/responses/UnauthorizedError'
 *      404:
 *        $ref: '#/components/responses/NotFound'
 *      500:
 *        $ref: '#/components/responses/DatabaseError'
 */
router.delete('/write/:id', authRequired, async (req, res) => {
  // Pull submission ID out of the URL parameter
  const { id } = req.params;

  crudOperationsManager.update(res, Submissions.deleteWritingSubmission, 'Submission', id);
});

/**
 * @swagger
 * /submission/write/{id}:
 *  delete:
 *    summary: Attempts to delete the drawn submission with the specified submission ID.
 *    security:
 *      - okta: []
 *    tags:
 *      - Submissions
 *    parameters:
 *      - $ref: '#/components/parameters/submissionId'
 *    responses:
 *      204:
 *        $ref: '#/components/responses/EmptySuccess'
 *      401:
 *        $ref: '#/components/responses/UnauthorizedError'
 *      404:
 *        $ref: '#/components/responses/NotFound'
 *      500:
 *        $ref: '#/components/responses/DatabaseError'
 */
router.delete('/draw/:id', authRequired, async (req, res) => {
  // Pull submission ID out of the URL parameter
  const { id } = req.params;

  crudOperationsManager.update(res, Submissions.deleteDrawingSubmission, 'Submission', id);
});

module.exports = router;