Cash Register Freecodecamp project – failing tests 18 and 19

I am trying to solve the FreeCodeCamp cash register challenge and am meeting all tests apart from tests 18 and 19. I’m confused as to why my code is not meeting those tests (particularly for 19, as the output I am getting seems to match what they want) and would appreciate some advice.

  1. When price is 19.5, the value in the #cash element is 20, cid is [[“PENNY”, 0.5], [“NICKEL”, 0], [“DIME”, 0], [“QUARTER”, 0], [“ONE”, 0], [“FIVE”, 0], [“TEN”, 0], [“TWENTY”, 0], [“ONE HUNDRED”, 0]], and the #purchase-btn element is clicked, the value in the #change-due element should be “Status: CLOSED PENNY: $0.5”.

  2. When price is less than the value in the #cash element, total cash in drawer cid is equal to change due, and the #purchase-btn element is clicked, the value in the #change-due element should be “Status: CLOSED” with change due in coins and bills sorted in highest to lowest order.

`

                // Variables
                let price = 19.5;
                let cid = [
                  ["PENNY", .5],
                  ["NICKEL", 0],
                  ["DIME", 0],
                  ["QUARTER", 0],
                  ["ONE", 0],
                  ["FIVE", 0],
                  ["TEN", 0],
                  ["TWENTY", 20],
                  ["ONE HUNDRED", 0],
                ];
                
                // Denomination values
                const denomValues = {
                  PENNY: 0.01,
                  NICKEL: 0.05,
                  DIME: 0.1,
                  QUARTER: 0.25,
                  ONE: 1,
                  FIVE: 5,
                  TEN: 10,
                  TWENTY: 20,
                  "ONE HUNDRED": 100,
                };
                
                // Helper to handle floating-point precision
                function precise(num) {
                  return parseFloat(num.toFixed(2));
                }
                
                // Calculate total cash in the drawer
                function sum(arr) {
                  return arr.reduce((acc, curr) => acc + curr[1], 0);
                }
                
                let totalCashInDrawer = sum(cid);
                
                // DOM elements
                let changeOwed = document.getElementById("change-due");
                let moneyAmount = document.getElementById("cash");
                let buyObjects = document.getElementById("purchase-btn");
                
                // Purchase function
                function purchaseItem() {
                  let moneyNumber = parseFloat(moneyAmount.value);
                
                  if (isNaN(moneyNumber)) {
                    alert("Invalid input! Please enter a valid amount.");
                    changeOwed.innerText = "";
                    moneyAmount.value = "";
                    return;
                  }
                
                  let moneyOwedToCustomer = precise(moneyNumber - price);
                
                  if (moneyNumber < price) {
                    changeOwed.innerText = "Status: INSUFFICIENT_FUNDS";
                    alert("Customer does not have enough money to purchase the item.");
                    moneyAmount.value = "";
                  } else if (moneyOwedToCustomer > 0 && totalCashInDrawer < moneyOwedToCustomer) {
                    changeOwed.innerText = "Status: INSUFFICIENT_FUNDS";
                  } else if (moneyOwedToCustomer === totalCashInDrawer) {
                    returnChange(moneyOwedToCustomer);
                    moneyAmount.value = "";
                  } else if (moneyOwedToCustomer > 0) {
                    returnChange(moneyOwedToCustomer);
                  } else if (moneyNumber === price) {
                    changeOwed.innerHTML = "No change due - customer paid with exact cash";
                    moneyAmount.value = "";
                  }
                }
                
                function returnChange(moneyOwedToCustomer) {
                  let originalCID = JSON.parse(JSON.stringify(cid)); // Deep copy of original CID
                  let reversedCID = [...cid].reverse();
                  let finalAmount = { status: "OPEN", change: [] };
                
                  reversedCID.forEach(function (arr) {
                    let denomination = arr[0];
                    let totalAvailableInDenomination = arr[1];
                    let denominationValue = denomValues[denomination];
                    let amountToReturn = 0;
                
                    while (moneyOwedToCustomer >= denominationValue && totalAvailableInDenomination > 0) {
                      moneyOwedToCustomer = precise(moneyOwedToCustomer - denominationValue);
                      totalAvailableInDenomination = precise(totalAvailableInDenomination - denominationValue);
                      amountToReturn = precise(amountToReturn + denominationValue);
                    }
                
                    if (amountToReturn > 0) {
                      finalAmount.change.push([denomination, precise(amountToReturn)]);
                    }
                  });
                
                  // ✅ Update `cid` before checking "CLOSED"
                  cid = cid.map(([denomination, total]) => {
                    let returnedAmount = finalAmount.change.find(([d]) => d === denomination)?.[1] || 0;
                    return [denomination, precise(total - returnedAmount)];
                  });
                
                  // ✅ Update total cash in drawer
                  totalCashInDrawer = sum(cid);
                
                  // ✅ Correct check for "CLOSED" status
                
                  if (totalCashInDrawer === 0) {
                  finalAmount.status = "CLOSED";
                  finalAmount.change = reversedCID.filter(([_, amount]) => amount > 0); // Only keep denominations with cash
                }
                
                  if (moneyOwedToCustomer > 0) {
                    changeOwed.innerText = "Status: INSUFFICIENT_FUNDS";
                  } else {
                    changeOwed.innerText = `Status: ${finalAmount.status} ${finalAmount.change
                      .map(([denomination, amount]) => `${denomination}: $${amount.toFixed(2)}`)
                      .join(", ")}`;
                  }
                }
                
                // Event listener
                buyObjects.addEventListener("click", purchaseItem);``

I have tried re-writing the closed status code multiple times, including using and removing filters, trying both reversedCID and originalCID, use of variables, moving code blocks etc. Nothing seems to be fixing the issue. The code for test 18 seems almost there.

k6 script HTTP GET fails when testing JPetStore

I’m totally new to k6 and a beginner in js. With some AI I’ve managed to write this easy k6 script to create some artificial traffic on JPetStore running locally.

import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  vus: 1, 
  duration: '5m',
};

const headers = {
  'Accept': '*/*',
  'Accept-Encoding': 'gzip, deflate, br, zstd'
};

const pages = [
  "/Catalog.action",
  '/Catalog.action?viewCategory=&categoryId=FISH',
  '/Catalog.action?viewCategory=&categoryId=DOGS',
  '/Catalog.action?viewCategory=&categoryId=REPTILES',
  '/Catalog.action?viewCategory=&categoryId=CATS',
  '/Catalog.action?viewCategory=&categoryId=BIRDS',
  '/Account.action?signonForm=',
  '/Account.action?newAccountForm='
];

function randomString(length) {
  const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  let result = '';
  for (let i = 0; i < length; i++) {
    result += chars.charAt(Math.floor(Math.random() * chars.length));
  }
  return result;
}

export default function () {
  const randomPage = pages[Math.floor(Math.random() * pages.length)];
  const res = http.get(`http://localhost:8080/jpetstore/actions${randomPage}`, { headers });
  check(res, { 'status 200': (r) => r.status === 200 });

  if (randomPage === '/Account.action?signonForm=' || randomPage === '/Account.action?newAccountForm=' ) {
    const payload = {
      username: randomString(8),
      password: randomString(8),
    };
    const loginRes = http.post(`http://localhost:8080/jpetstore/actions${randomPage}`, payload);
    check(loginRes, { 'login attempt': (r) => r.status === 200 });
  }

  sleep(Math.random() * 3);
}

Then i launch it with k6 run k6_jpet_test.js --http-debug="full"

And i get this error:

INFO[0000] Request:
GET /jpetstore/actions/Catalog.action HTTP/1.1
Host: localhost:8080
User-Agent: k6/0.56.0 (https://k6.io/)
Accept-Encoding: gzip

group= iter=0 request_id=4e419454-4be5-4a2d-6925-211c0afc0556 scenario=default source=http-debug vu=1
WARN[0000] Request Failed                                error="Get "http://localhost:8080/jpetstore/actions/Catalog.action": dial tcp 127.0.0.1:8080: connect: connection refused"

JPetStore is running on TomCat 90 on the localhost:8080/jpetstore. If i copy and paste the address k6 tried in a browser, it works.

Any idea? Thanks

CSS Arrow with any angle but fixed start and end point

I am currently working on a side project, where I want to “draw” diagrams. At the moment you just drag “sticky notes” to a grid, move, resize and label them. I now want to connect these notes with arrows. I got the calculations for length (pythagoras) and the angle of the line down.

calculateAngle(): number {
    return Math.atan2(this._start.y - this._end.y, this._start.x - this._end.x) * 180 / Math.PI + 180;
}

calculateLength(): number {
    return Math.round(Math.sqrt(Math.pow(this._start.y - this._end.y, 2) + Math.pow(this._start.x - this._end.x, 2)));
}

I also found a simple CSS solution for the arrows which work perfectly for horizontal and vertical arrows, but as soon the angle isn’t dividable by 90deg the position is of course of.

This is based of a solution I found in SO and just added the transform. If you play around with the deg value, you can see how the base and head move around in the 2D space:
https://jsfiddle.net/0r7k6L4c/

Does anyone know a good way to calculate the “new” top and left values if the rotation is taken into account? Or maybe I just offset the position with margins if this calulation is easier.

I used to be good at math in school but that was a few decades ago.

Does dynamically loading header content via a linked JavaScript file affect SEO?

I am teaching an HTML5 class and one student did this for his header:

<script src="elements/header.js"></script>
    <script>
      header("Home");
    </script>

The linked file looks like this:

function header(name){
    document.write(`
        
        <header
      style="
        text-align: center;
        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
      "
    >
      <h1>Science Fiction</h1>
      <h2>${name}</h2>
    </header>
    <hr />
        
    `);
}

He also did this for the footer and navbar. It works, but in all my years of web development, I’ve never seen it done this way. For one thing, I see no reason to include CSS in a linked JavaScript file when you could just put it in a linked CSS file. But beyond that, I’m wondering if web developers don’t do this because it might affect SEO. Does dynamically linking to content prevent that content from being indexed by search engines? This is for a student project so SEO doesn’t matter, just wondering from a best practices standpoint.

How to prevent data loss when updating nested objects in Node.js?

I have an object called productionSheet which contains details of a plastic bag. Dimensions and other information are stored inside productionSheet.bagDetails.
When my app’s backend receives the productionSheet object from the frontend, the data must be passed to a function that calculates the bag’s weight and adds the result to the object before saving it in the database. However, this operation overwrites other data within the object itself.
Let me explain:

Backend router

productionSheetsRouter.post("/", checkJwt, async (req, res) => {
  try {
    let newProductionSheet = new ProductionSheet(req.body);
    newProductionSheet = calculateWeightSingleBag(newProductionSheet);

    await newProductionSheet.save();
    res.status(201).json(newProductionSheet);
  } catch (error) {
    console.error("Error in productionSheetsRouter.post:", error);
    res.status(400).json({ message: "Bad Request" });
  }
});

This is the calculateWeightSingleBag() function:

const calculateWeightSingleBag = (productionSheet) => {
  const widthDevelopment =
    Number(productionSheet.bagDetails.input.dimensions.width.value) +
    Number(productionSheet.bagDetails.input.gussets.openSideGusset.value);

  const heightDevelopment =
    Number(productionSheet.bagDetails.input.dimensions.height.value) +
    Number(productionSheet.bagDetails.input.flaps.upperFlapOpen.value) +
    Number(productionSheet.bagDetails.input.flaps.zipFlap.value) +
    Number(productionSheet.bagDetails.input.gussets.openBottomGusset.value) / 2;

  const heightDevelopmentNet =
    Number(productionSheet.bagDetails.input.dimensions.height.value) +
    Number(productionSheet.bagDetails.input.flaps.upperFlapOpen.value) / 2 +
    Number(productionSheet.bagDetails.input.flaps.zipFlap.value) +
    Number(productionSheet.bagDetails.input.gussets.openBottomGusset.value) / 2;

  const bareWeight = (
    widthDevelopment *
    heightDevelopment *
    2 *
    (Number(productionSheet.bagDetails.output.thickness.value) / 10000) *
    Number(productionSheet.bagDetails.output.specificWeight.value)
  ).toFixed(2);

  const netDieCutWeight = (
    widthDevelopment *
    heightDevelopmentNet *
    2 *
    (Number(productionSheet.bagDetails.output.thickness.value) / 10000) *
    Number(productionSheet.bagDetails.output.specificWeight.value) *
    (1 - Number(productionSheet.bagDetails.input.cutting.cuttingDie.value) / 100)
  ).toFixed(2);
  

  console.log("Before bagweight: ", productionSheet.bagWeight);
  productionSheet.bagWeight = {
    input: {
      ...productionSheet.bagWeight.input,
    },
    output: {
      ...productionSheet.bagWeight.output, 
      bareWeight: { value: bareWeight, cost: false, unit: "g" },
      netDieCutWeight: { value: netDieCutWeight, cost: false, unit: "g" },
    },
  };
  console.log("After bagweight: ", productionSheet.bagWeight);

  return productionSheet; 
};

export default calculateWeightSingleBag;

I have this result from the console.log():

Before bagweight:  {
  input: { netDieCutWeight: { value: 0, cost: false, unit: 'g' } },
  output: {
    bareWeight: { value: 0, cost: false, unit: 'g' },
    netDieCutWeight: { value: 0, cost: false, unit: 'g' },
    netDieCutWeightWithAccessories: { value: 0, cost: false, unit: 'g' }
  }
}
After bagweight:  {
  output: {
    bareWeight: { value: 1.56, cost: false, unit: 'g' },
    netDieCutWeight: { value: 1.47, cost: false, unit: 'g' }
  }
}

After bagweight should be:

  input: { netDieCutWeight: { value: 0, cost: false, unit: 'g' } },
  output: {
    bareWeight: { value: 1.56, cost: false, unit: 'g' },
    netDieCutWeight: { value: 1.47, cost: false, unit: 'g' }
    netDieCutWeightWithAccessories: { value: 0, cost: false, unit: 'g' }
  }
}```

What is the best practice to do that?

How can I create a snowflake to google sheets add-on internally?

I’m creating an internal google sheets add-on that will allow users to run queries from their snowflake and update the data into their google sheets automatically on a schedule. The snowflake connection is proving difficult within apps script, does anyone know how to set this up? Also it may be easier to set up this functionality if I could write the add-on in say python for example (but I’m not sure how hosting/deployment would work if I did this).

Connecting to Postgres database using javascript

Apologies if this is a bad question but I’ve been troubleshooting for a while now and don’t understand where the issue lies.

I have a db.js file that is meant to login and connect to my local postgres database. It pulls the login information from a .env file. When I run debugger on the db.js file I am able to connect and the login information shows in the console as loading correctly.
I have an app.js file that is calling the connectDb function which is exported from my db.js file. When I run the debugger or try to run the app through the command line I get the error below:
Error connecting to the database: error: role "your-username" does not exist"

Below is the code block from app.js where I’m trying to call the connectDb function from db.js.

  try {
    await connectDb(); // Wait for DB connection before starting the server
    app.listen(PORT, () => {
      console.log(`Server running on port ${PORT}`);
    });
  } catch (error) {
    console.error('Failed to start the server due to DB connection error:', error);
    process.exit(1); // Exit the application in case of DB connection failure
  }
};

And just in case it’s helpful below is the db.js file:

require('dotenv').config();
console.log('DB_USER:', process.env.DB_USER);
console.log('DB_PASSWORD:', process.env.DB_PASSWORD);
console.log('DB_HOST:', process.env.DB_HOST);
console.log('DB_NAME:', process.env.DB_NAME);

const { Pool } = require('pg');

const pool = new Pool({
  user: process.env.DB_USER,
  host: process.env.DB_HOST,
  database: process.env.DB_NAME,
  password: process.env.DB_PASSWORD,
  port: process.env.DB_PORT,
});

console.log('Connecting with user: ', process.env.DB_USER);

const connectDb = async () => {
  try {
    await pool.connect();
    console.log('Connected to the database');
  } catch (error) {
    console.error('Error connecting to the database:', error);
    process.exit(1); // Exit the application in case of DB connection failure
  }
};

module.exports = { connectDb };

It feels like there’s some timing issue going on between the two and the connectDb function is using default values but I’ve tried to log the function both before and during the call and both show the correct login information. I don’t see anywhere in my .env file that indicates a “your-username” should exist. I’ve even tried hardcoding in the values into the db.js file and the issue still occurs.

Can anyone offer insight into my issue? Thanks in advance!

Firebase Optimistic Locking Duplicate Processing

I have two Firebase functions that run hourly and process the same list of users. They share a batch document(this.batchId: MM-dd-yyyy-HH so it’s unique for each hour) and use transactions to coordinate processing. Each instance gets a batch of users after a specific ID (lastProcessedId) and updates the batch document with:

  • A new lastProcessedId
  • A global totalCount increment
  • Instance-specific counts and processed IDs

The global totalCount is always correct, however, sometimes the instance-specific fields show that both instances processed some of the same IDs (A batch of two usually). This conflicts with how i understand optimistic locking to work – why aren’t the transactions preventing this overlap in processing? Any advice or insight would be apprechiated.

private async getNextBatchTransaction(): Promise<{ userDocs: QueryDocumentSnapshot<DocumentData>[] | null, needsCleanup: boolean }> {
  return this.firestore.runTransaction(async (transaction) => {
    const batchRef = this.firestore.collection("batch_sequence").doc(this.batchId);
    const batchDoc = await transaction.get(batchRef);

    const data = (batchDoc.exists ? batchDoc.data() : {
      lastProcessedId: null,
      complete: false,
    }) as BatchDocument;

    if (data.complete) {
      return { userDocs: null };
    }

    let query = this.firestore
      .collection("users")
      .orderBy("__name__")
      .limit(this.batchSize);

    if (data.lastProcessedId) {
      query = query.startAfter(data.lastProcessedId);
    }

    const userSnapshot = await transaction.get(query);

    if (userSnapshot.empty) {
      transaction.set(
        batchRef,
        { complete: true },
        { merge: true }
      );
      return { userDocs: null };
    }

    const batchLength = userSnapshot.docs.length;
    const lastDoc = userSnapshot.docs[batchLength - 1];
    const processedIds = userSnapshot.docs.map(doc => doc.id);
    
    transaction.set(
      batchRef,
      {
        lastProcessedId: lastDoc.id,
        totalCount: FieldValue.increment(batchLength),
        [`instance.${this.instanceId}`]: FieldValue.increment(batchLength),
        [`processedIds.${this.instanceId}`]: FieldValue.arrayUnion(...processedIds),
      },
      { merge: true }
    );

    return { userDocs: userSnapshot.docs};
  });
}

Firebase Functions “TypeError: Cannot read properties of undefined (reading ‘document’)” Despite Correct Imports

I’m encountering a persistent “TypeError: Cannot read properties of undefined (reading ‘document’)” error when deploying my Firebase Cloud Functions, even though my import statements and code appear to be correct. This error occurs when trying to define a Firestore trigger using functions.firestore.v2.document(...).

Code:

const functions = require("firebase-functions");
const admin = require("firebase-admin");
const axios = require("axios");
const { FieldValue } = require('firebase-admin/firestore');

admin.initializeApp();
const db = admin.firestore();

exports.rahh = functions.firestore.v2.document("user/{userId}").onCreate(async (event) => {
    // ... (My function logic here - fetching data from Google People API) ...
});

Error Message:

TypeError: Cannot read properties of undefined (reading ‘document’)
at Object. (C:pathtomyfunctionsindex.js:9:39)
… (Rest of the stack trace) …

Problem:

Despite having the correct import (const functions = require("firebase-functions");) and initializing the Firebase Admin SDK (admin.initializeApp();), the firestore property on the functions object is undefined, causing the error.

What I’ve Tried:

  • Emulator Reset: firebase emulators:stop, firebase emulators:clear, firebase emulators:start –only functions

  • Node Version: Switched to Node 18 (using nvm).

  • Emulator Run: When running on the emulator it worked perfectly.

  • Package Lock File: Removed package-lock.json and node_modules, then npm install

  • Global Firebase CLI: npm install -g firebase-tools

  • Simplified index.js: Created a minimal index.js with a simple HTTPS function (and that worked!)

  • Checked main in package.json: The main field is correctly set to “index.js”.

  • Double-checked for typos: Confirmed no typos in imports or function calls.

  • Used a basic text editor: Edited index.js in Notepad to rule out IDE issues.

package.json:

{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "scripts": { /* ... */ },
  "engines": { "node": "18" },
  "main": "index.js",
  "dependencies": {
    "axios": "^1.7.9",
    "firebase": "^11.2.0", // Firebase client SDK (might not be needed in functions)
    "firebase-admin": "^13.0.2",
    "firebase-functions": "^6.3.1"
  },
  "devDependencies": { /* ... */ },
  "private": true
}

Firebase CLI Version: 13.29.3

The fact that a new project works points to a configuration issue, but I can’t identify it.

What could be causing this “undefined” error, even with the correct imports and after trying all the troubleshooting steps above?

Validation Error with Express Validator and Multer in Node.js

I’m working on a Node.js backend using Express, and I’m encountering a validation error when trying to create a new post with file uploads. Despite providing the required data in the form-data section of Postman, I’m getting a validation error indicating that the title and content fields are empty. However, my images are being successfully stored in Cloudinary.

Here is my setup:

Middleware (uploadImage.js):

const cloudinary = require("cloudinary").v2;
const { CloudinaryStorage } = require("multer-storage-cloudinary");
const multer = require("multer");

// Configure Cloudinary storage for multer
const storage = new CloudinaryStorage({
  cloudinary: cloudinary,
  params: {
    folder: "post/uploads",
    public_id: (req, file) => file.originalname,
    resource_type: "image", // Ensure the resource type is image
    transformation: [
      { width: 1000, crop: "scale" }, // Resize the image to a width of 1000 pixels
      { quality: "auto:best" }, // Automatically adjust the best quality
      { fetch_format: "auto" }, // Automatically convert to the best format
    ],
  },
});

// Multer upload middleware
const upload = multer({ storage }).fields([
  { name: "imageUri", maxCount: 1 },
  { name: "thumbnails", maxCount: 4 },
]);

module.exports = upload;

Routes (postRoutes.js):

const express = require("express");
const router = express.Router();
const { body } = require("express-validator");
const postController = require("../controller/postController");
const upload = require("../middleware/uploadImage");

router.get("/posts", postController.getPosts);
router.post(
  "/posts/new",
  [
    body("title")
      .trim()
      .isLength({ min: 5 })
      .notEmpty()
      .withMessage("Title is required"),
    body("content")
      .trim()
      .isLength({ min: 5 })
      .notEmpty()
      .withMessage("Content is required"),
  ],
  upload,
  postController.createPost
);

router.get("/posts/:id", postController.getPostById);

router.put(
  "/posts/:id",
  [
    body("title")
      .trim()
      .isLength({ min: 5 })
      .notEmpty()
      .withMessage("Title is required"),

    body("content")
      .trim()
      .isLength({ min: 5 })
      .notEmpty()
      .withMessage("Content is required"),
  ],
  postController.updatePostById
);

router.delete("/posts/:id", postController.deletePostById);

module.exports = router;

Controller (postController.js):

exports.createPost = async (req, res, next) => {
  console.log("Request Body:", req.body);
  console.log("Request Files:", req.files);
  const { title, content } = req.body;
  const error = validationResult(req);

  if (!error.isEmpty()) {
    return res.status(400).json({
      status: "Failed",
      code: 400,
      message: "Validation failed",
      errors: error.array(),
    });
  }

  try {
    const imageUri = req.files.imageUri ? req.files.imageUri[0].path : null;
    const thumbnails = req.files.thumbnails ? req.files.thumbnails.map(file => file.path) : [];

    const post = new Post({
      title,
      content,
      imageUri,
      thumbnails,
    });

    const result = await post.save();

    return res.status(201).json({
      status: "Success",
      code: 201,
      message: "Post created successfully",
      data: result,
    });
  } catch (error) {
    return res.status(500).json({
      status: "Failed",
      code: 500,
      message: "An error occured while creating post",
      error,
    });
  }
};

Model (postModel.js):

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

const postSchema = new Schema(
  {
    title: {
      type: String,
      required: true,
    },
    content: {
      type: String,
      required: true,
    },
    imageUri: {
      type: String,
      required: false,
    },
    thumbnails: {
      type: [String],
      required: false,
    },
  },
  { timestamps: true }
);

module.exports = mongoose.model("post", postSchema);

Server Setup (server.js):

require("dotenv").config();
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const postRoutes = require("./routes/postRoutes");
const cloudinary = require('./config/CloudinaryConfig')

const hostname = "localhost";
const port = 8080;

const MONGODB_URI = process.env.MONGODB_URI

const app = express();

app.use(bodyParser.json());

app.use((req, res, next) => {
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader("Access-Control-Allow-Methods", "GET , POST , PUT , DELETE");
  res.setHeader("Access-Control-Allow-Headers", "Content-Type , Authorization");
  next();
});

app.use("/", postRoutes);

mongoose
  .connect(MONGODB_URI)
  .then(() => {
    console.log("Connected to database");
    app.listen(port, hostname, () => {
      console.log(`Server is running at http://${hostname}:${port}`);
    });
  })
  .catch((err) => {
    console.log(err);
  });

Request in Postman:

  • Method: POST

  • URL: http://localhost:3000/api/posts/new

  • Body: form-data

    • title: First Post
    • content: Hello World
    • imageUri:(file)
    • thumbnails: (file)
      fom-data
      headers

Logs from the server:

[nodemon] starting `node app.js`
Connected to database
Server is running at http://localhost:8080
Request Body: [Object: null prototype] {
  title: 'First Post',
  content: 'Hello World'
}
Request Files: [Object: null prototype] {
  imageUri: [
    {
      fieldname: 'imageUri',
      originalname: 'Leonardo_Kino_XL_wildlife_jungle_and_include_all_animals_2.jpg',
      encoding: '7bit',
      mimetype: 'image/jpeg',
      path: 'https://res.cloudinary.com/du9ze60lr/image/upload/v1738605266/post/uploads/Leonardo_Kino_XL_wildlife_jungle_and_include_all_animals_2.jpg.jpg',
      size: 190411,
      filename: 'post/uploads/Leonardo_Kino_XL_wildlife_jungle_and_include_all_animals_2.jpg'
    }
  ],
  thumbnails: [
    {
      fieldname: 'thumbnails',
      originalname: 'NEW_Vision.webp',
      encoding: '7bit',
      mimetype: 'image/webp',
      path: 'https://res.cloudinary.com/du9ze60lr/image/upload/v1738605268/post/uploads/NEW_Vision.webp.png',
      size: 48171,
      filename: 'post/uploads/NEW_Vision.webp'
    }
  ]
}

Despite providing the data, I’m getting the following validation error in Postman

{
  "status": "Failed",
  "code": 400,
  "message": "Validation failed",
  "errors": [
    { "type": "field", "value": "", "msg": "Invalid value", "path": "title", "location": "body" },
    { "type": "field", "value": "", "msg": "Title is required", "path": "title", "location": "body" },
    { "type": "field", "value": "", "msg": "Invalid value", "path": "content", "location": "body" },
    { "type": "field", "value": "", "msg": "Content is required", "path": "content", "location": "body" }
  ]
}

Question: Why am I getting validation errors for the title and content fields even though they are provided in the request? How can I resolve this issue? Additionally, why are my images being successfully stored in Cloudinary despite the validation errors?

I’d Appreciate Some help! Thanks!!

Safer regex for number formatting [duplicate]

Right now I’m using the regex below for number formatting, e.g.

numberInString.replace(/B(?=(d{3})+(?!d))/g, ','); // e.g. 123456 => 123,456

and sonarqube considers it to be a dangerous

Make sure the regex used here, which is vulnerable to super-linear
runtime due to backtracking, cannot lead to denial of service.

I have tried also this one:

/(?<=d)(?=(d{3})+(?!d))/g

I can’t write any other regex, so do you have any ideas how to change it?

How to efficiently check if two line segments intersect?

I’ve referenced this answer (has an interactive desmos visualization) in a related question to develop this Javascript function:

function doLineSegmentsIntersect(a1X, a1Y, a2X, a2Y, b1X, b1Y, b2X, b2Y) {
  const dxA = a2X - a1X;
  const dyA = a2Y - a1Y;
  const dxB = b2X - b1X;
  const dyB = b2Y - b1Y;

  // Calculate cross product values to determine orientation
  const p0 = dyB * (b2X - a1X) - dxB * (b2Y - a1Y);
  const p1 = dyB * (b2X - a2X) - dxB * (b2Y - a2Y);
  const p2 = dyA * (a2X - b1X) - dxA * (a2Y - b1Y);
  const p3 = dyA * (a2X - b2X) - dxA * (a2Y - b2Y);

  // The segments intersect if the products of these cross products are non-positive (i.e. the segments straddle each other)
  return (p0 * p1 <= 0) && (p2 * p3 <= 0);
}

I assume this is the most efficient way to calculate this.

I desire these properties:

  1. Line segments should not be considered intersecting just because they share a vertex
  2. Line segments that overlap should be considered intersecting
  3. Line segments shouldn’t be considered intersecting just because they share the same slope

With the current solution above, lines that overlap are considered intersecting (this is good). The problem is that they are also considered intersecting if they are not touching but they are in a line (this is bad). In addition, whenever they share a vertex, they are also considered intersecting (this is also bad).

We can improve some things by changing this line:

return (p0 * p1 <= 0) && (p2 * p3 <= 0);

To this:

return (p0 * p1 < 0) && (p2 * p3 < 0);

Now, when they’re in a line but otherwise not touching, they are no longer considered intersecting (this is good). In addition, they can also share a vertex and not be considered intersecting (this is also good). The problem is that now when they overlap completely, they are no longer considered intersecting (which we had with the previous solution).

Is there a way to concisely satisfy all desired properties?

The problem with <= is:

The problem with < is:

Dynamically created file download via AJAX. (No file on server. ‘Content-Disposition’ = ‘attachment’) [duplicate]

I have an API that accepts a file upload from a web form, does some validation work, then response with an XML file created on the fly. (The response has the content-disposition header set to “attachment”.) This API will handle a lot of requests, so we don’t want the response files saved to the server’s file system.

Due to limitations on the client side, I am making the API request via AJAX. I could probably rework it to use an http request if necessary.

The only answers I’ve been able to find involve creating an anchor, setting window.location, etc. triggering a secondary request to the server to retrieve the file. But since we don’t save the file on the server, this won’t work.

Is there any way to deliver the AJAX (or HTTP) response as a file download?

Loading a php-generated external Json array into a Vis.js Timeline, extracting data from a Google Sheet spreadsheet

Following this example, I’ve been trying to pass a php-generated Json array into the timeline, with no success unfortunately.

  // load data via an ajax request. When the data is in, load the timeline
  $.ajax({
    dataType: 'json',
    url: 'http://mywebsite.com/json.php',
    success: function (data) {
      // hide the "loading..." message
      document.getElementById('loading').style.display = 'none';

      // DOM element where the Timeline will be attached
      var container = document.getElementById('visualization');

      // Create a DataSet (allows two way data-binding)
      var items = new vis.DataSet(data);

      // Configuration for the Timeline
      var options = {};

      // Create a Timeline
      var timeline = new vis.Timeline(container, items, options);
    },
    error: function (err) {
      console.log('Error', err);
      if (err.status === 0) {
        alert('Failed to load data/basic.json.nPlease run this example on a server.');
      }
      else {
        alert('Failed to load data/basic.json.');
      }
    }
  });

The .php page extracts data from a Google Sheet spreadsheet
Google Sheet Spreadsheet

 <?php
 header("Content-type: application/json");
$json = file_get_contents('https://sheets.googleapis.com/v4/spreadsheets/MySheet/values/base?key=MyAPIKey');

$originalArray = json_decode($json, true);

$keys = ["id", "etichetta", "content", "details", "start", "end"];
$rows = array_slice($originalArray['values'], 1);

$data = [];
foreach($rows as $i => $row) {
    array_unshift($row, (string)($i + 1));
    
    $data[] = array_combine($keys, $row);
}

$output = json_encode($data);
echo $output;
?>

And this is the outcome:

[{"id":"1","etichetta":"successione papi","content":"Gregorio xvi","Dettagli":"Bartolomeo Alberto Mauro Cappellani di Belluno due","start":"6 febbraio 1831","end":"1 giugno 1846"},{"id":"2","etichetta":"letteratura","content":"i Promessi sposi","Dettagli":"periodo di pubblicazione dell'edizione "quarantana", la piu00f9 definitiva","start":"1 marzo 1840","end":"1 marzo 1840"},{"id":"3","etichetta":"Giolitti","content":"nascita di Giolitti","Dettagli":"","start":"27 ottobre 1842","end":"27 ottobre 1842"}]

I know there may be several kinds of issues here: Data serialization may be bad in the first place, or the php code may be simply inappropriate (it was taken from a previous Datatables project, where it worked fine); or may be the date format.

What’s your opinion? Thanks

ps: I edited both the php and javascript code following the nice advice from ADyson and Barmar

How to show the date picker if I click the parent div after explictly hiding the date type input in React?

So, I am trying to create a component that will show your typical date picker if an user clicks anywhere in the parent div. But I don’t want to show the date type input.

<div className="flex flex-row gap-3">
    <div className="p-3 ... rounded bg-white cursor-pointer">
        <p className="font-normal text-sm ...">{date}</p>
        <input type="date" className="hidden" />
    </div>
    <div>{...}</div>
</div>