Repository navigation
Expand file tree
/
Copy pathapp.js
More file actions
228 lines (193 loc) · 7.06 KB
/
Copy pathapp.js
File metadata and controls
228 lines (193 loc) · 7.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
/*
* Description: Provides the API endpoints
* for my math dojo. There are two endpoints:
* 1. GET — sends back a randomly generated
* math practice problem
* 2. Also GET - sends back the answer of
* a math practice problem provided by the
* user of my API
*/
'use strict';
/**
* Import express library, which allows us to
* respond to and receive http requests.
* This is similar to importing java classes,
* like scanner or arrays
*/
const express = require('express');
// instantiate an instance of the express
const app = express();
/**
* multer is the node module needed for us to
* parse data from POST requests which are in the
* form of forms and json
*/
const multer = require("multer");
app.use(multer().none());
// give node the ability to parse JSON
// also limit the size of incoming data to 1 mb max
// to prevent a large influx of data
app.use(express.json({limit: "1mb"}));
/**
* Require sqlite and sqlite3 modules
* in this project.
* -sqlite3 provides the code/functionality
* for reading and writing to a database
* -sqlite adds promises to sqlite3
*/
const sqlite3 = require("sqlite3");
const sqlite = require("sqlite");
/**
* require the MathFunction class that I created
* this will allow me to actually make MathFunction
* objects in this file
*/
const MathFunction = require("./MathFunction.js");
// define API endpoint GET request for getting randomy-generated math problems
app.get("/practice", sendArithmeticProblems);
// define API endpoint GET request for getting the answer to a math problem
app.get("/solve/:expression", sendBackAnswer);
// deine API endpoint GET request for getting previously attempted problems from database
app.get("/retrieve", sendPreviouslySolvedProblems);
// define API endpoint POST request for sending the problem entry to the backend
app.post("/store-problem", storeInDatabase);
async function sendPreviouslySolvedProblems(request, response) {
const db = await getDBConnection("problems_solved.db");
let queryForCorrectlySolvedProblems = "SELECT * FROM correct";
let queryForIncorrectlySolvedProblems = "SELECT * FROM incorrect";
try {
const correctEntries = await db.all(queryForCorrectlySolvedProblems);
const incorrectEntries = await db.all(queryForIncorrectlySolvedProblems);
console.log(correctEntries);
response.json({
"correct": correctEntries,
"incorrect": incorrectEntries
});
} catch(error) {
response.type("text").status(500).send("An error occured on the server.");
}
}
async function storeInDatabase(request, response) {
let solvedProblem = request.body.solvedProblem;
let userAnswer = request.body.userAnswer;
let problemEntry = "Problem: " + solvedProblem
+ ", your answer: " + userAnswer;
let solvedCorrectly = request.body.solvedCorrectly;
const db = await getDBConnection("problems_solved.db");
let insertProblemQuery = "";
if (solvedCorrectly) {
insertProblemQuery = "INSERT INTO correct (entry) VALUES ($entry)";
} else {
insertProblemQuery = "INSERT INTO incorrect (entry) VALUES ($entry)";
}
try {
await db.run(insertProblemQuery, {$entry: problemEntry});
await db.close(); // close the connection to the database once we're done
} catch(error) {
console.log("error: " + error);
response.status(500).send("Error on the server. Please try again later.");
}
}
/**
* Kick-starts the process of generating random arithmetic problems,
* then sends the problems back to the API caller in JSON format.
* @param {Request} request - Not applicable for this endpoint, since
* the API caller doesn't need to specify any params. But by convention
* this param is here
* @param {Response} response - response object that will contain the JSON
* of practice problems to send back to the API caller
*/
function sendArithmeticProblems(request, response) {
let practiceProblems = generateArithmeticProblems();
response.type("json").json(practiceProblems);
}
/**
* generate an array of random math expressions and return them
* @returns {JSON} - return a JSON of math problems, each in the
* form of a string
*/
function generateArithmeticProblems() {
let problems = {};
// generate 100 problems
const PROBLEMAMOUNT = 100;
for (let i = 0; i < PROBLEMAMOUNT; i++) {
let randomProblem = generateArithmeticProblem();
problems[i] = randomProblem;
}
return problems;
}
/**
* generates a single randomly generated
* math problem(math expression)
* @returns {String} - return a randomly generated
* math problem(math expression)
*/
function generateArithmeticProblem() {
let problem = "";
const MAXAMOUNTOFTERMS = 3;
const MINAMOUNTOFTERMS = 2;
let numberOfTerms = Math.floor(Math.random() * MAXAMOUNTOFTERMS) +
MINAMOUNTOFTERMS;
let operators = ["+", "-", "*"];
const MINNUMBER = 1;
const MAXNUMBER = 9;
let randomNum;
const MAXINDEX = 3;
// fencepost algorithm(stop before last term)
for (let i = 0; i < numberOfTerms - 1; i++) {
// generate random num between 1 and 100(inclusive)
randomNum = Math.floor(Math.random() * MAXNUMBER) + MINNUMBER;
let operatorIndex = Math.floor(Math.random() * MAXINDEX);
let randomOperator = operators[operatorIndex];
problem += randomNum + " " + randomOperator + " ";
}
// generate random num between 1 and 100(inclusive)
randomNum = Math.floor(Math.random() * MAXNUMBER) + MINNUMBER;
problem += randomNum;
return problem;
}
/**
* This function gets called when the API caller makes a GET request
* to solve a particular math problem. This function is responsible for
* kick-starting the problem solving process and also returning the answer
* back to the API caller
* @param {Request} request - object that contains the route parameter
* that we need. The route param is the math problem that the API caller
* wants us to solve.
* @param {Response} response - response that we'll return back to the
* API caller
*/
function sendBackAnswer(request, response) {
let expression = request.params["expression"];
expression = new MathFunction(expression);
let answer = expression.computeExpression();
// if answer got returned null, then something was wrong with the input format
if (answer === null) {
// send an error code back
let errorMessage = "Given problem {" + expression + "} is not a valid expression!";
const ERRORNUM = 400;
response.type('text').status(ERRORNUM);
response.send(errorMessage);
} else {
response.type("text");
response.send(answer);
}
}
// Establishes a database connection to the database and
// returns the database object. * Any errors that occur should
// be caught in the function that calls this one.
// @param {string} dbFilePath the relative location to store
// this database * @returns {Object} - The database object for
// the connection.
async function getDBConnection(dbFilePath) {
const db = await sqlite.open({
filename: dbFilePath,
driver: sqlite3.Database
});
return db;
}
app.use(express.static('public'));
// listen on some port number; listen for new requests to come in
const PORTNUM = 8000;
const PORT = process.env.PORT || PORTNUM;
app.listen(PORT);