Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions exercisefiles/node/colorUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Exercise 6: Node path rules

const fs = require('fs');

// Load colors from JSON file
const colors = JSON.parse(fs.readFileSync('./colors.json', 'utf8'));

/**
* Returns the hex color code for a given color name
* @param {string} colorName - The name of the color
* @returns {string|null} - The hex code or null if not found
*/
function returnColorCode(colorName) {
const color = colors.find(c => c.color.toLowerCase() === colorName.toLowerCase());
return color ? color.code.hex : null;
}

module.exports = {
returnColorCode
};
29 changes: 29 additions & 0 deletions exercisefiles/node/countryData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Exercise 6: Node path rules

// Array of European countries with their ISO codes
const europeanCountries = [
{ country: 'Germany', isoCode: 'DE' },
{ country: 'France', isoCode: 'FR' },
{ country: 'Italy', isoCode: 'IT' },
{ country: 'Spain', isoCode: 'ES' },
{ country: 'Poland', isoCode: 'PL' },
{ country: 'Romania', isoCode: 'RO' },
{ country: 'Netherlands', isoCode: 'NL' },
{ country: 'Belgium', isoCode: 'BE' },
{ country: 'Greece', isoCode: 'GR' },
{ country: 'Portugal', isoCode: 'PT' },
{ country: 'Sweden', isoCode: 'SE' },
{ country: 'Austria', isoCode: 'AT' },
{ country: 'Hungary', isoCode: 'HU' },
{ country: 'Switzerland', isoCode: 'CH' },
{ country: 'Denmark', isoCode: 'DK' },
{ country: 'Finland', isoCode: 'FI' },
{ country: 'Norway', isoCode: 'NO' },
{ country: 'Ireland', isoCode: 'IE' },
{ country: 'Croatia', isoCode: 'HR' },
{ country: 'Bulgaria', isoCode: 'BG' }
];

module.exports = {
europeanCountries
};
18 changes: 18 additions & 0 deletions exercisefiles/node/dateUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Exercise 6: Node path rules

/**
* Calculates the number of days between two dates
* @param {string} date1 - First date in YYYY-MM-DD format
* @param {string} date2 - Second date in YYYY-MM-DD format
* @returns {number} - Number of days between the dates
*/
function daysBetweenDates(date1, date2) {
const d1 = new Date(date1);
const d2 = new Date(date2);
const diffTime = Math.abs(d2 - d1);
return Math.ceil(diffTime / (1000 * 60 * 60 * 24));
}

module.exports = {
daysBetweenDates
};
38 changes: 38 additions & 0 deletions exercisefiles/node/fileUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Exercise 6: Node path rules

const fs = require('fs');
const readline = require('readline');

/**
* Reads a file line by line and returns lines containing "Fusce"
* @returns {Promise<Array<string>>} - Promise that resolves with an array of matching lines
*/
async function getLineByLineFromTextFile() {
return new Promise((resolve, reject) => {
const lines = [];
const fileStream = fs.createReadStream('./sample.txt');

const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});

rl.on('line', (line) => {
if (line.includes('Fusce')) {
lines.push(line);
}
});

rl.on('close', () => {
resolve(lines);
});

rl.on('error', (error) => {
reject(error);
});
});
}

module.exports = {
getLineByLineFromTextFile
};
212 changes: 26 additions & 186 deletions exercisefiles/node/nodeserver.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Exercise 6: nodeserver file rules
// write a nodejs server that will expose a method call "get" that will return the value of the key passed in the query string
// example: http://localhost:3000/get?key=hello
// if the key is not passed, return "key not passed"
Expand All @@ -6,201 +7,40 @@
// when server is listening, log "server is listening on port 3000"

// Import required Node.js modules
const http = require('http'); // For creating the HTTP server
const url = require('url'); // For parsing URL query strings
const fs = require('fs'); // For file system operations
const readline = require('readline'); // For reading files line by line
const http = require('http');
const url = require('url');

// Load colors from JSON file
const colors = JSON.parse(fs.readFileSync('./colors.json', 'utf8'));
// Import utility modules
const { validatePhoneNumber, validateSpanishDNI } = require('./validators');
const { returnColorCode } = require('./colorUtils');
const { daysBetweenDates } = require('./dateUtils');

/**
* Validates a US phone number in the format XXX-XXX-XXXX
* @param {string} phoneNumber - The phone number to validate
* @returns {boolean} - True if valid, false otherwise
*/
function validatePhoneNumber(phoneNumber) {
const regex = /^\d{3}-\d{3}-\d{4}$/;
return regex.test(phoneNumber);
}

/**
* Validates a Spanish DNI (8 digits followed by a letter)
* The letter is calculated based on the number
* @param {string} dni - The DNI to validate
* @returns {boolean} - True if valid, false otherwise
*/
function validateSpanishDNI(dni) {
const dniRegex = /^(\d{8})([A-Z])$/;
const match = dni.match(dniRegex);
if (!match) return false;

const number = parseInt(match[1], 10);
const letter = match[2];
const letters = 'TRWAGMYFPDXBNJZSQVHLCKE';
const expectedLetter = letters[number % 23];

return letter === expectedLetter;
}

/**
* Returns the hex color code for a given color name
* @param {string} colorName - The name of the color
* @returns {string|null} - The hex code or null if not found
*/
function returnColorCode(colorName) {
const color = colors.find(c => c.color.toLowerCase() === colorName.toLowerCase());
return color ? color.code.hex : null;
}

/**
* Calculates the number of days between two dates
* @param {string} date1 - First date in YYYY-MM-DD format
* @param {string} date2 - Second date in YYYY-MM-DD format
* @returns {number} - Number of days between the dates
*/
function daysBetweenDates(date1, date2) {
const d1 = new Date(date1);
const d2 = new Date(date2);
const diffTime = Math.abs(d2 - d1);
return Math.ceil(diffTime / (1000 * 60 * 60 * 24));
}

// Array of European countries with their ISO codes
// Used by the /RandomEuropeanCountry endpoint
const europeanCountries = [
{ country: 'Germany', isoCode: 'DE' },
{ country: 'France', isoCode: 'FR' },
{ country: 'Italy', isoCode: 'IT' },
{ country: 'Spain', isoCode: 'ES' },
{ country: 'Poland', isoCode: 'PL' },
{ country: 'Romania', isoCode: 'RO' },
{ country: 'Netherlands', isoCode: 'NL' },
{ country: 'Belgium', isoCode: 'BE' },
{ country: 'Greece', isoCode: 'GR' },
{ country: 'Portugal', isoCode: 'PT' },
{ country: 'Sweden', isoCode: 'SE' },
{ country: 'Austria', isoCode: 'AT' },
{ country: 'Hungary', isoCode: 'HU' },
{ country: 'Switzerland', isoCode: 'CH' },
{ country: 'Denmark', isoCode: 'DK' },
{ country: 'Finland', isoCode: 'FI' },
{ country: 'Norway', isoCode: 'NO' },
{ country: 'Ireland', isoCode: 'IE' },
{ country: 'Croatia', isoCode: 'HR' },
{ country: 'Bulgaria', isoCode: 'BG' }
];

// Function to read file line by line and return lines containing "Fusce"
// Returns a Promise that resolves with an array of matching lines
function getLineByLineFromTextFile() {
return new Promise((resolve, reject) => {
const lines = []; // Array to store matching lines
const fileStream = fs.createReadStream('./sample.txt'); // Create read stream for the file // Create read stream for the file

// Create readline interface to process file line by line
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity // Recognize all instances of CR LF as a single line break
});

// Event handler for each line read from the file
rl.on('line', (line) => {
if (line.includes('Fusce')) { // Check if line contains "Fusce"
lines.push(line); // Add matching line to results array
}
});

// Event handler when file reading is complete
rl.on('close', () => {
resolve(lines); // Resolve promise with all matching lines
});

// Event handler for any errors during file reading
rl.on('error', (error) => {
reject(error); // Reject promise with error
});
});
}
// Import route handlers
const { handleGetRoute } = require('./routes/getRoute');
const { handleDaysRoute } = require('./routes/daysRoute');
const { handleFileRoute } = require('./routes/fileRoute');
const { handleCountryRoute } = require('./routes/countryRoute');
const { handleHealthRoute } = require('./routes/healthRoute');

// Create HTTP server with request handler
const server = http.createServer((req, res) => {
// Parse the incoming request URL and extract components
const parsedUrl = url.parse(req.url, true);
const pathname = parsedUrl.pathname; // Get the path (e.g., '/get')
const query = parsedUrl.query; // Get query parameters as an object
const pathname = parsedUrl.pathname;
const query = parsedUrl.query;

// Route: /get?key=value
// Returns a greeting with the provided key parameter
if (pathname === '/get') {
const key = query.key; // Extract 'key' from query parameters
if (key) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello ' + key); // Return greeting with the key
} else {
res.writeHead(400, { 'Content-Type': 'text/plain' });
res.end('key not passed'); // Return error if key is missing
}
}
// Route: /DaysBetweenDates?date1=YYYY-MM-DD&date2=YYYY-MM-DD
// Calculates the number of days between two dates
else if (pathname === '/DaysBetweenDates') {
const date1 = query.date1; // First date parameter
const date2 = query.date2; // Second date parameter

if (date1 && date2) {
const d1 = new Date(date1); // Parse first date
const d2 = new Date(date2); // Parse second date
const diffTime = Math.abs(d2 - d1); // Calculate time difference in milliseconds
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); // Convert to days

res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end(`Days between ${date1} and ${date2}: ${diffDays}`);
} else {
res.writeHead(400, { 'Content-Type': 'text/plain' });
res.end('date1 and date2 parameters are required'); // Return error if dates are missing
}
}
// Route: /GetLineByLineFromTextFile
// Reads sample.txt and returns lines containing "Fusce"
else if (pathname === '/GetLineByLineFromTextFile') {
getLineByLineFromTextFile()
.then(lines => {
// Success: return matching lines as JSON with count
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ lines: lines, count: lines.length }));
})
.catch(error => {
// Error: return error message
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('Error reading file: ' + error.message);
});
}
// Route: /RandomEuropeanCountry
// Returns a randomly selected European country with its ISO code
else if (pathname === '/RandomEuropeanCountry') {
const randomIndex = Math.floor(Math.random() * europeanCountries.length); // Generate random index
const randomCountry = europeanCountries[randomIndex]; // Get country at random index

// Return the country and ISO code as JSON
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
country: randomCountry.country,
isoCode: randomCountry.isoCode
}));
}
/**
* Route: /health
* Simple health-check endpoint for monitoring
*/
else if (pathname === '/health') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ status: 'ok' }));
}
// Default route: handle all unrecognized paths
else {
handleGetRoute(query, res);
} else if (pathname === '/DaysBetweenDates') {
handleDaysRoute(query, res);
} else if (pathname === '/GetLineByLineFromTextFile') {
handleFileRoute(res);
} else if (pathname === '/RandomEuropeanCountry') {
handleCountryRoute(res);
} else if (pathname === '/health') {
handleHealthRoute(res);
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('method not supported'); // Return 404 for unsupported routes
res.end('method not supported');
}
});

Expand Down
5 changes: 4 additions & 1 deletion exercisefiles/node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@
"keywords": [],
"author": "",
"license": "ISC",
"description": ""
"description": "",
"devDependencies": {
"mocha": "^11.7.5"
}
}
22 changes: 22 additions & 0 deletions exercisefiles/node/routes/countryRoute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Exercise 6: Node path rules

const { europeanCountries } = require('../countryData');

/**
* Handles the /RandomEuropeanCountry endpoint
* @param {object} res - HTTP response object
*/
function handleCountryRoute(res) {
const randomIndex = Math.floor(Math.random() * europeanCountries.length);
const randomCountry = europeanCountries[randomIndex];

res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
country: randomCountry.country,
isoCode: randomCountry.isoCode
}));
}

module.exports = {
handleCountryRoute
};
Loading