Add exercise tracker certification project

This commit is contained in:
CherryKitten 2022-10-25 08:51:36 +02:00
parent 1097d1dc85
commit 6a04a0400e
Signed by: sammy
GPG key ID: 0B696A86A853E955
11 changed files with 979 additions and 0 deletions

View file

@ -0,0 +1,3 @@
# Tell Linguist to exclude HTML files to help Replit language detection.
*.html linguist-vendored
*.css linguist-vendored

View file

@ -0,0 +1,2 @@
.env
node_modules

View file

@ -0,0 +1 @@
.replit

View file

@ -0,0 +1,10 @@
run = "npm start"
entrypoint = "index.js"
[packager]
language = "nodejs"
[packager.features]
packageSearch = true
guessImports = true
enabledForHosting = false

View file

@ -0,0 +1,3 @@
# Exercise Tracker
This is the boilerplate for the Exercise Tracker project. Instructions for building your project can be found at https://www.freecodecamp.org/learn/apis-and-microservices/apis-and-microservices-projects/exercise-tracker

View file

@ -0,0 +1,83 @@
const express = require('express')
const app = express()
const cors = require('cors')
require('dotenv').config()
const users = [];
function User(username, id) {
this.username = username;
this._id = id;
this.log = [];
}
users.push(new User('testUser', '0'))
app.use(cors())
app.use(express.static('public'))
app.use(express.json()) // for parsing application/json
app.use(express.urlencoded({ extended: true })) // for parsing application/x-www-form-urlencoded
app.get('/', (req, res) => {
res.sendFile(__dirname + '/views/index.html')
});
app.route('/api/users')
.get((req, res) => {
res.json(users)
})
.post((req, res) => {
const id = users.length
const username = req.body.username
users.push(new User(username, id))
res.json({username: username, _id: id})
})
app.post('/api/users/:_id/exercises', (req, res) => {
const description = req.body.description;
const duration = +req.body.duration;
const date = req.body.date;
const id = req.params._id;
const user = users[id]
if (!duration || !description){
return res.json({error: 'missing parameters'})
} else {
let dateString;
if (date) {
dateString = new Date(date).toDateString()
} else {
dateString = new Date().toDateString()
}
user.log.push({description: description, duration: duration, date: dateString});
user.count = user.log.length;
res.json({
username: user.username,
description: description,
duration: duration,
date: dateString,
_id: user._id
})
}
})
app.route('/api/users/:_id/logs')
.get((req, res) => {
const id = req.params._id;
const limit = Number(req.query.limit) || 0;
const response = users[id];
let newlog = response.log
if (req.query.from && req.query.to) {
const from = new Date(req.query.from).getTime();
const to = new Date(req.query.to).getTime();
newlog = newlog.filter(item => from <= new Date(item.date).getTime() <= to)}
if (limit > 0){
newlog = newlog.slice(0, limit)
}
response.log = newlog
res.json(response)
})
const listener = app.listen(process.env.PORT || 3000, () => {
console.log('Your app is listening on port ' + listener.address().port)
})

View file

@ -0,0 +1,749 @@
{
"name": "fcc-exercise-tracker",
"version": "0.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "fcc-exercise-tracker",
"version": "0.1.0",
"license": "MIT",
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"express": "^4.16.4"
}
},
"node_modules/accepts": {
"version": "1.3.7",
"license": "MIT",
"dependencies": {
"mime-types": "~2.1.24",
"negotiator": "0.6.2"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/array-flatten": {
"version": "1.1.1",
"license": "MIT"
},
"node_modules/body-parser": {
"version": "1.19.0",
"license": "MIT",
"dependencies": {
"bytes": "3.1.0",
"content-type": "~1.0.4",
"debug": "2.6.9",
"depd": "~1.1.2",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"on-finished": "~2.3.0",
"qs": "6.7.0",
"raw-body": "2.4.0",
"type-is": "~1.6.17"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/bytes": {
"version": "3.1.0",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/content-disposition": {
"version": "0.5.3",
"license": "MIT",
"dependencies": {
"safe-buffer": "5.1.2"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/content-type": {
"version": "1.0.4",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/cookie": {
"version": "0.4.0",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/cookie-signature": {
"version": "1.0.6",
"license": "MIT"
},
"node_modules/cors": {
"version": "2.8.5",
"license": "MIT",
"dependencies": {
"object-assign": "^4",
"vary": "^1"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/debug": {
"version": "2.6.9",
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/depd": {
"version": "1.1.2",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/destroy": {
"version": "1.0.4",
"license": "MIT"
},
"node_modules/dotenv": {
"version": "8.2.0",
"license": "BSD-2-Clause",
"engines": {
"node": ">=8"
}
},
"node_modules/ee-first": {
"version": "1.1.1",
"license": "MIT"
},
"node_modules/encodeurl": {
"version": "1.0.2",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/escape-html": {
"version": "1.0.3",
"license": "MIT"
},
"node_modules/etag": {
"version": "1.8.1",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/express": {
"version": "4.17.1",
"license": "MIT",
"dependencies": {
"accepts": "~1.3.7",
"array-flatten": "1.1.1",
"body-parser": "1.19.0",
"content-disposition": "0.5.3",
"content-type": "~1.0.4",
"cookie": "0.4.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "~1.1.2",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "~1.1.2",
"fresh": "0.5.2",
"merge-descriptors": "1.0.1",
"methods": "~1.1.2",
"on-finished": "~2.3.0",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
"proxy-addr": "~2.0.5",
"qs": "6.7.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.1.2",
"send": "0.17.1",
"serve-static": "1.14.1",
"setprototypeof": "1.1.1",
"statuses": "~1.5.0",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
},
"engines": {
"node": ">= 0.10.0"
}
},
"node_modules/finalhandler": {
"version": "1.1.2",
"license": "MIT",
"dependencies": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"on-finished": "~2.3.0",
"parseurl": "~1.3.3",
"statuses": "~1.5.0",
"unpipe": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/forwarded": {
"version": "0.1.2",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/fresh": {
"version": "0.5.2",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/http-errors": {
"version": "1.7.2",
"license": "MIT",
"dependencies": {
"depd": "~1.1.2",
"inherits": "2.0.3",
"setprototypeof": "1.1.1",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/iconv-lite": {
"version": "0.4.24",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/inherits": {
"version": "2.0.3",
"license": "ISC"
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
"license": "MIT",
"engines": {
"node": ">= 0.10"
}
},
"node_modules/media-typer": {
"version": "0.3.0",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/merge-descriptors": {
"version": "1.0.1",
"license": "MIT"
},
"node_modules/methods": {
"version": "1.1.2",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime": {
"version": "1.6.0",
"license": "MIT",
"bin": {
"mime": "cli.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/mime-db": {
"version": "1.44.0",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.27",
"license": "MIT",
"dependencies": {
"mime-db": "1.44.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/ms": {
"version": "2.0.0",
"license": "MIT"
},
"node_modules/negotiator": {
"version": "0.6.2",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/on-finished": {
"version": "2.3.0",
"license": "MIT",
"dependencies": {
"ee-first": "1.1.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/parseurl": {
"version": "1.3.3",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/path-to-regexp": {
"version": "0.1.7",
"license": "MIT"
},
"node_modules/proxy-addr": {
"version": "2.0.6",
"license": "MIT",
"dependencies": {
"forwarded": "~0.1.2",
"ipaddr.js": "1.9.1"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/qs": {
"version": "6.7.0",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.6"
}
},
"node_modules/range-parser": {
"version": "1.2.1",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/raw-body": {
"version": "2.4.0",
"license": "MIT",
"dependencies": {
"bytes": "3.1.0",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/safe-buffer": {
"version": "5.1.2",
"license": "MIT"
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"license": "MIT"
},
"node_modules/send": {
"version": "0.17.1",
"license": "MIT",
"dependencies": {
"debug": "2.6.9",
"depd": "~1.1.2",
"destroy": "~1.0.4",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "~1.7.2",
"mime": "1.6.0",
"ms": "2.1.1",
"on-finished": "~2.3.0",
"range-parser": "~1.2.1",
"statuses": "~1.5.0"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/send/node_modules/ms": {
"version": "2.1.1",
"license": "MIT"
},
"node_modules/serve-static": {
"version": "1.14.1",
"license": "MIT",
"dependencies": {
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "0.17.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/setprototypeof": {
"version": "1.1.1",
"license": "ISC"
},
"node_modules/statuses": {
"version": "1.5.0",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/toidentifier": {
"version": "1.0.0",
"license": "MIT",
"engines": {
"node": ">=0.6"
}
},
"node_modules/type-is": {
"version": "1.6.18",
"license": "MIT",
"dependencies": {
"media-typer": "0.3.0",
"mime-types": "~2.1.24"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/unpipe": {
"version": "1.0.0",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/utils-merge": {
"version": "1.0.1",
"license": "MIT",
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/vary": {
"version": "1.1.2",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
}
},
"dependencies": {
"accepts": {
"version": "1.3.7",
"requires": {
"mime-types": "~2.1.24",
"negotiator": "0.6.2"
}
},
"array-flatten": {
"version": "1.1.1"
},
"body-parser": {
"version": "1.19.0",
"requires": {
"bytes": "3.1.0",
"content-type": "~1.0.4",
"debug": "2.6.9",
"depd": "~1.1.2",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"on-finished": "~2.3.0",
"qs": "6.7.0",
"raw-body": "2.4.0",
"type-is": "~1.6.17"
}
},
"bytes": {
"version": "3.1.0"
},
"content-disposition": {
"version": "0.5.3",
"requires": {
"safe-buffer": "5.1.2"
}
},
"content-type": {
"version": "1.0.4"
},
"cookie": {
"version": "0.4.0"
},
"cookie-signature": {
"version": "1.0.6"
},
"cors": {
"version": "2.8.5",
"requires": {
"object-assign": "^4",
"vary": "^1"
}
},
"debug": {
"version": "2.6.9",
"requires": {
"ms": "2.0.0"
}
},
"depd": {
"version": "1.1.2"
},
"destroy": {
"version": "1.0.4"
},
"dotenv": {
"version": "8.2.0"
},
"ee-first": {
"version": "1.1.1"
},
"encodeurl": {
"version": "1.0.2"
},
"escape-html": {
"version": "1.0.3"
},
"etag": {
"version": "1.8.1"
},
"express": {
"version": "4.17.1",
"requires": {
"accepts": "~1.3.7",
"array-flatten": "1.1.1",
"body-parser": "1.19.0",
"content-disposition": "0.5.3",
"content-type": "~1.0.4",
"cookie": "0.4.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "~1.1.2",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "~1.1.2",
"fresh": "0.5.2",
"merge-descriptors": "1.0.1",
"methods": "~1.1.2",
"on-finished": "~2.3.0",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
"proxy-addr": "~2.0.5",
"qs": "6.7.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.1.2",
"send": "0.17.1",
"serve-static": "1.14.1",
"setprototypeof": "1.1.1",
"statuses": "~1.5.0",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
}
},
"finalhandler": {
"version": "1.1.2",
"requires": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"on-finished": "~2.3.0",
"parseurl": "~1.3.3",
"statuses": "~1.5.0",
"unpipe": "~1.0.0"
}
},
"forwarded": {
"version": "0.1.2"
},
"fresh": {
"version": "0.5.2"
},
"http-errors": {
"version": "1.7.2",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.3",
"setprototypeof": "1.1.1",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.0"
}
},
"iconv-lite": {
"version": "0.4.24",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"inherits": {
"version": "2.0.3"
},
"ipaddr.js": {
"version": "1.9.1"
},
"media-typer": {
"version": "0.3.0"
},
"merge-descriptors": {
"version": "1.0.1"
},
"methods": {
"version": "1.1.2"
},
"mime": {
"version": "1.6.0"
},
"mime-db": {
"version": "1.44.0"
},
"mime-types": {
"version": "2.1.27",
"requires": {
"mime-db": "1.44.0"
}
},
"ms": {
"version": "2.0.0"
},
"negotiator": {
"version": "0.6.2"
},
"object-assign": {
"version": "4.1.1"
},
"on-finished": {
"version": "2.3.0",
"requires": {
"ee-first": "1.1.1"
}
},
"parseurl": {
"version": "1.3.3"
},
"path-to-regexp": {
"version": "0.1.7"
},
"proxy-addr": {
"version": "2.0.6",
"requires": {
"forwarded": "~0.1.2",
"ipaddr.js": "1.9.1"
}
},
"qs": {
"version": "6.7.0"
},
"range-parser": {
"version": "1.2.1"
},
"raw-body": {
"version": "2.4.0",
"requires": {
"bytes": "3.1.0",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
}
},
"safe-buffer": {
"version": "5.1.2"
},
"safer-buffer": {
"version": "2.1.2"
},
"send": {
"version": "0.17.1",
"requires": {
"debug": "2.6.9",
"depd": "~1.1.2",
"destroy": "~1.0.4",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "~1.7.2",
"mime": "1.6.0",
"ms": "2.1.1",
"on-finished": "~2.3.0",
"range-parser": "~1.2.1",
"statuses": "~1.5.0"
},
"dependencies": {
"ms": {
"version": "2.1.1"
}
}
},
"serve-static": {
"version": "1.14.1",
"requires": {
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "0.17.1"
}
},
"setprototypeof": {
"version": "1.1.1"
},
"statuses": {
"version": "1.5.0"
},
"toidentifier": {
"version": "1.0.0"
},
"type-is": {
"version": "1.6.18",
"requires": {
"media-typer": "0.3.0",
"mime-types": "~2.1.24"
}
},
"unpipe": {
"version": "1.0.0"
},
"utils-merge": {
"version": "1.0.1"
},
"vary": {
"version": "1.1.2"
}
}
}

View file

@ -0,0 +1,22 @@
{
"name": "fcc-exercise-tracker",
"version": "0.1.0",
"description": "A REST API project, part of Free Code Camp's curriculum",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"dotenv": "^8.2.0",
"express": "^4.16.4",
"cors": "^2.8.5"
},
"repository": {
"url": "https://github.com/freeCodeCamp/boilerplate-project-exercisetracker"
},
"license": "MIT",
"keywords": [
"node",
"express"
]
}

View file

@ -0,0 +1,59 @@
* {
box-sizing: border-box;
}
body {
font-family:sans-serif;
margin: 25px;
color: #222;
background-color: #f5f5f5;
}
h1 {
font-weight: bold;
}
p {
max-width: 900px;
}
form {
margin-bottom: 25px;
padding: 15px;
background-color: #87D37C;
display: inline-block;
width: 100%;
max-width: 340px;
border-radius: 5px;
}
input {
display: block;
margin-bottom: 10px;
padding: 5px;
width: 100%;
border: 1px solid lightgrey;
border-radius: 3px;
font-size: 16px;
}
input[type=submit] {
font-size: 16px;
border-radius: 3px;
background-color: #E4F1FE;
border: 1px solid grey;
box-shadow: 2px 2px #999;
cursor: pointer;
}
input[type=submit]:hover {
background-color: #FFFEC4;
}
code {
font-family: monospace;
font-size: 1.2em;
background-color: #FFFEC4;
padding: 2px;
}

View file

@ -0,0 +1 @@
PORT=3000

View file

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<title>Exercise Tracker | freeCodeCamp</title>
<link rel="shortcut icon" href="https://cdn.freecodecamp.org/universal/favicons/favicon.ico" type="image/x-icon" />
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet" type="text/css" />
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="container">
<h1>Exercise tracker</h1>
<form action="/api/users" method="post">
<h3>Create a New User</h3>
<p><code>POST /api/users</code></p>
<input id="uname" type="text" name="username" placeholder="username" />
<input type="submit" value="Submit" />
</form>
<form id="exercise-form" method="post">
<h3>Add exercises</h3>
<p><code>POST /api/users/:_id/exercises</code></p>
<input id="uid" type="text" name=":_id" placeholder=":_id" />
<input id="desc" type="text" name="description" placeholder="description*" />
<input id="dur" type="text" name="duration" placeholder="duration* (mins.)" />
<input id="date" type="text" name="date" placeholder="date (yyyy-mm-dd)" />
<input type="submit" value="Submit" />
</form>
<p>
<strong>GET user's exercise log: </strong>
<code>GET /api/users/:_id/logs?[from][&amp;to][&amp;limit]</code>
</p>
<p><strong>[ ]</strong> = optional</p>
<p><strong>from, to</strong> = dates (yyyy-mm-dd); <strong>limit</strong> = number</p>
</div>
<script>
const exerciseForm = document.getElementById("exercise-form");
exerciseForm.addEventListener("submit", () => {
const userId = document.getElementById("uid").value;
exerciseForm.action = `/api/users/${userId}/exercises`;
exerciseForm.submit();
});
</script>
</body>
</html>