parent
d69a6b2e71
commit
9169b06caf
30
.gitignore
vendored
Normal file
30
.gitignore
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# my additions
|
||||
logs
|
||||
dist
|
||||
db/main
|
||||
*deleteme*
|
||||
*fortesting*
|
41
README.md
41
README.md
@ -1,2 +1,43 @@
|
||||
# food_diary
|
||||
Food Diary UI
|
||||
|
||||
## What
|
||||
Simple application for entering food choices and whether they caused any issues
|
||||
such as headaches, migraines, upset digestion, etc.
|
||||
|
||||
## Installation / How To Run
|
||||
This project assumes an apt-based OS. It is currently being developed on Ubuntu.
|
||||
|
||||
Clone the project:
|
||||
|
||||
`git clone https://github.com/Hyperling/food_diary food_diary_app`
|
||||
|
||||
Move into the directory:
|
||||
|
||||
`cd food_diary_app`
|
||||
|
||||
Run the project:
|
||||
|
||||
`./run.sh`
|
||||
|
||||
### Different Environments
|
||||
The project can also safely run the project from another directory so that it's
|
||||
safe to be called from things like cron or if you're feeling lazy and don't want
|
||||
to move your terminal location.
|
||||
|
||||
Such as something like this for doing development testing:
|
||||
|
||||
`bash ~/Projects/git/food_diary_app`
|
||||
|
||||
Or maybe something like these in a more production-like environment:
|
||||
|
||||
`bash /opt/FoodDiary/run.sh`
|
||||
|
||||
`bash /usr/local/src/food_diary_app/run.sh`
|
||||
|
||||
#### Caveat
|
||||
These create `package*.json` files in the local directory which will need
|
||||
cleaned or ignored. The `node_modules` folder is moved to the project directory.
|
||||
|
||||
## Testing
|
||||
`test.sh` has been provided for showing how to interact with the APIs.
|
||||
|
8
db/DDL/journal.sql
Normal file
8
db/DDL/journal.sql
Normal file
@ -0,0 +1,8 @@
|
||||
CREATE TABLE journal (
|
||||
user_id INTEGER NOT NULL,
|
||||
cal_date TEXT NOT NULL,
|
||||
meal TEXT NOT NULL,
|
||||
food TEXT NOT NULL,
|
||||
caused_issue INTEGER NOT NULL,
|
||||
comments TEXT
|
||||
) STRICT;
|
3442
package-lock.json
generated
Normal file
3442
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
26
package.json
Normal file
26
package.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "food_diary",
|
||||
"version": "0.0.1",
|
||||
"description": "Food Diary UI for researching dietary sensitivities.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Hyperling/food_diary.git"
|
||||
},
|
||||
"author": "Hyperling",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/Hyperling/food_diary/issues"
|
||||
},
|
||||
"homepage": "https://github.com/Hyperling/food_diary#readme",
|
||||
"dependencies": {
|
||||
"@types/node": "^18.14.6",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"package.json": "^2.0.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"sqlite3": "^5.1.4",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"removedDependencies": {}
|
||||
}
|
80
run.sh
Executable file
80
run.sh
Executable file
@ -0,0 +1,80 @@
|
||||
#!/bin/bash
|
||||
# Date: 2023-03-07
|
||||
# Developer: Hyperling
|
||||
# Purpose: Install all dependencies and run the project.
|
||||
|
||||
DIR=`dirname $0`
|
||||
PROG=`basename $0`
|
||||
if [[ $DIR == "." ]]; then
|
||||
DIR="`pwd`"
|
||||
echo $DIR/$PROG
|
||||
fi
|
||||
|
||||
## Install any system packages. ##
|
||||
|
||||
if [[ -z `which npm` || -z `which tsc` || -z `which sqlite` ]]; then
|
||||
echo "A dependency is missing, going through install process."
|
||||
sudo apt install npm node-typescript sqlite
|
||||
else
|
||||
echo "All packages are available."
|
||||
fi
|
||||
|
||||
## Install/update any project modules. ##
|
||||
|
||||
# Ensure it is safe to be running an npm nstall.
|
||||
if [[ `pwd` != $DIR && -e package.json ]]; then
|
||||
cat <<- EOF
|
||||
WARNING: It seems you are currently in a different JS project which already
|
||||
has a package.json. Cannot guarantee safety of installing $DIR. Please
|
||||
make sure you understand what you're doing before continuing.
|
||||
EOF
|
||||
printf "Would you like to continue? [N/y]: "
|
||||
typeset -u continue
|
||||
read continue
|
||||
if [[ $continue != Y* ]]; then
|
||||
echo "Good choice, exiting application."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Use package.json in project directory to evaluate if any modules need added.
|
||||
echo "Refreshing NPM packages."
|
||||
npm install $DIR
|
||||
|
||||
## Main ##
|
||||
|
||||
# Create any non-git directories.
|
||||
mkdir -p $DIR/logs
|
||||
|
||||
# Ensure all DB patches are applied.
|
||||
bash $DIR/setup_db.sh
|
||||
|
||||
# Compile the Javascript portion of the application.
|
||||
echo "Compiling..."
|
||||
touch $DIR/dist &&
|
||||
sh -c "rm -rv $DIR/dist" &&
|
||||
tsc --project $DIR &&
|
||||
ls -l $DIR/dist &&
|
||||
echo "Success!" || {
|
||||
echo "ERROR: Failed to compile."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Start backend in a forked process.
|
||||
echo "Starting back-end in a child process and sleeping for 5 seconds."
|
||||
mkdir -p $DIR/db
|
||||
node $DIR/dist/server.js "$DIR" >>$DIR/logs/server.log 2>&1 &
|
||||
sleep 5
|
||||
|
||||
# Start frontend.
|
||||
# ??? $DIR/dist/index.js >$DIR/logs/ui.log 2>&1
|
||||
echo "Started front-end successfully!" ||
|
||||
echo "Failed to start front-end."
|
||||
echo "Front-end service has stopped."
|
||||
|
||||
## Finish ##
|
||||
|
||||
# If we've reached this point then the front-end has been terminated and the
|
||||
# back-end needs to be stopped as well. use the helper script to do it
|
||||
echo "Finishing the back-end as well."
|
||||
$DIR/stop.sh
|
78
setup_db.sh
Executable file
78
setup_db.sh
Executable file
@ -0,0 +1,78 @@
|
||||
#!/bin/bash
|
||||
# Date: 2023-03-22
|
||||
# Developer: Hyperling
|
||||
# Purpose: Check if tables exist and if not then creates them
|
||||
|
||||
DIR=`dirname $0`
|
||||
PROG=`basename $0`
|
||||
if [[ $DIR == "." ]]; then
|
||||
DIR="`pwd`"
|
||||
echo $DIR/$PROG
|
||||
fi
|
||||
DB="$DIR/db/main"
|
||||
DEBUG="$1"
|
||||
|
||||
## Functions ##
|
||||
|
||||
function check_table {
|
||||
# Validate that the table exists in the database. If so then sqlite returns
|
||||
# the DDL used to create it and we return success (0). Otherwise fail (1).
|
||||
table_name="$1"
|
||||
echo "Checking for $table_name..."
|
||||
typeset -l result
|
||||
result=`
|
||||
sqlite3 $DB <<- EOF
|
||||
.schema $table_name
|
||||
EOF
|
||||
`
|
||||
[[ -n $DEBUG ]] && echo $result
|
||||
if [[ $result == *"create table $table_name"* ]]; then
|
||||
echo "Found it!"
|
||||
return 0
|
||||
fi
|
||||
echo "Table not found."
|
||||
return 1
|
||||
}
|
||||
|
||||
function run_ddl {
|
||||
#
|
||||
file_name="$1"
|
||||
echo "Running $file_name..."
|
||||
sqlite3 $DB <<- EOF
|
||||
.echo on
|
||||
.read $file_name
|
||||
EOF
|
||||
}
|
||||
|
||||
function list_ddl {
|
||||
# List the full path of the table files which need to be run.
|
||||
ls $DIR/db/DDL/*
|
||||
}
|
||||
|
||||
## Main ##
|
||||
echo "Ensuring DDL is applied and all patches are complete."
|
||||
|
||||
# Lop through tables and their DDL.
|
||||
list_ddl | while read table_file; do
|
||||
echo "*** $table_file ***"
|
||||
|
||||
# Get the name of the table based on the filename with no extension.
|
||||
table=`basename $table_file`
|
||||
table=${table//.sql/}
|
||||
|
||||
# Check for the table.
|
||||
check_table $table || {
|
||||
# If the check fails, run the create statement.
|
||||
run_ddl $table_file && {
|
||||
# If the create succeeds, check for the table.
|
||||
check_table $table || {
|
||||
# If the check fails (again), throw an error and quit.
|
||||
echo "ERROR: Could not create $table!"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
echo "Success!"
|
||||
done
|
||||
|
||||
exit 0
|
17
src/functions.ts
Normal file
17
src/functions.ts
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
// Date: 2023-03-07
|
||||
// Developer: Hyperling
|
||||
// Purpose: Keep main file clean by holding helper functions here.
|
||||
*/
|
||||
|
||||
import "objects.ts";
|
||||
|
||||
// Retrieve data from a connected database.
|
||||
function select_db () {
|
||||
null;
|
||||
}
|
||||
|
||||
// Send data to a connected database.
|
||||
function post_db () {
|
||||
null;
|
||||
}
|
7
src/includes.ts
Normal file
7
src/includes.ts
Normal file
@ -0,0 +1,7 @@
|
||||
/*
|
||||
// Date: 2023-03-07
|
||||
// Developer: Hyperling
|
||||
// Purpose: Keep main file clean by making sure all source code is available.
|
||||
*/
|
||||
|
||||
import "functions.ts";
|
13
src/index.tsx
Normal file
13
src/index.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
// Date: 2023-03-07
|
||||
// Developer: Hyperling
|
||||
// Purpose: Provide a UI for folks to log a food diary, providing a simple way
|
||||
// to enter the data and an easy way to filter/sort what caused issues.
|
||||
// Resources: Most helpful tutorials when learning Typescript and React.
|
||||
// https://blog.logrocket.com/how-use-typescript-react-tutorial-examples/
|
||||
*/
|
||||
|
||||
// Attach all the needed helpers.
|
||||
import "includes.ts";
|
||||
|
||||
/* Main, UI */
|
14
src/objects.ts
Normal file
14
src/objects.ts
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
// Date: 2023-03-07
|
||||
// Developer: Hyperling
|
||||
// Purpose: Keep main file clean by holding types (interfaces and vars) here.
|
||||
*/
|
||||
|
||||
interface record {
|
||||
user_id: number;
|
||||
cal_date: string;
|
||||
meal: string; // Only wants options: Breakfast, Lunch, Dinner, Snack.
|
||||
food: string;
|
||||
caused_issue: boolean; // 0 for true and 1 for false like Shell?
|
||||
comments: string;
|
||||
}
|
57
src/server.js
Normal file
57
src/server.js
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
// Date: 2023-03-07
|
||||
// Developer: Hyperling
|
||||
// Purpose: Provide an API for the UI to hit, decoupling the DB code.
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
/* Usage */
|
||||
|
||||
function usage (exit_code) {
|
||||
console.log(
|
||||
process.argv[1] + " is used to expose the SQLite backend to React.\n" +
|
||||
" It accepts the following parameters: \n" +
|
||||
" -h or --help: Display this usage text.\n" +
|
||||
" /path/to/project: Where the project lives and the db + scripts exist."
|
||||
);
|
||||
process.exit(exit_code);
|
||||
}
|
||||
|
||||
/* Arguments */
|
||||
|
||||
let DIR = "";
|
||||
if (process.argv.length == 2 || process.argv.length >= 4 || process.argv[2] == undefined) {
|
||||
console.log('Expected one argument!');
|
||||
usage(1);
|
||||
} else if (process.argv[2] === "-h" || process.argv[2] === "--help") {
|
||||
usage(0);
|
||||
} else {
|
||||
DIR = process.argv[2];
|
||||
console.log("Successfully got DIR: ", DIR);
|
||||
}
|
||||
|
||||
/* Setup */
|
||||
|
||||
const sqlite3 = require('sqlite3').verbose();
|
||||
|
||||
async function finish () {
|
||||
await db.close();
|
||||
}
|
||||
|
||||
/* Main Program */
|
||||
|
||||
async function main() {
|
||||
console.log("Connecting to DB "+DIR+"/db/main");
|
||||
let db = await new sqlite3.Database(DIR+"/db/main");
|
||||
console.log(db);
|
||||
try {
|
||||
let r = await db.run(`
|
||||
SELECT count(*) FROM journal
|
||||
`);
|
||||
} catch (e) {
|
||||
console.log("ERROR: The journal table could not be selected ", e);
|
||||
}
|
||||
console.log("The journal table current contains", r, " records.")
|
||||
}
|
||||
|
||||
main();
|
40
stop.sh
Executable file
40
stop.sh
Executable file
@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
# Date: 2023-03-07
|
||||
# Developer: Hyperling
|
||||
# Purpose: Turn off the project since the subprocesses run as forks.
|
||||
|
||||
DIR=`dirname $0`
|
||||
PROG=`basename $0`
|
||||
if [[ $DIR == "." ]]; then
|
||||
DIR="`pwd`"
|
||||
echo $DIR/$PROG
|
||||
fi
|
||||
|
||||
## Stop Frontend Services ##
|
||||
# Kill the frontend if it's still rnning for some reason.
|
||||
# ???
|
||||
|
||||
## Stop Backend Services ##
|
||||
|
||||
# Let backend know it's time to close then loop over status until it stops.
|
||||
echo "Stopping the backend service."
|
||||
# curl POST localhost:8080/stop
|
||||
count=1
|
||||
still_up="Y"
|
||||
while [[ $still_up == "Y" ]]; do
|
||||
echo "Check #$count"
|
||||
if (( $count >= 20 )); then
|
||||
# Force kill backend if we have gone through 20 rounds.
|
||||
killall $DIR/dist/server.js
|
||||
fi
|
||||
|
||||
# curl GET localhost:8080/check_status
|
||||
status=$?
|
||||
|
||||
if [[ $status != 0 ]]; then
|
||||
still_up="N"
|
||||
fi
|
||||
|
||||
count=$(( count + 1 ))
|
||||
sleep 1
|
||||
done
|
43
test.sh
Executable file
43
test.sh
Executable file
@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
# Date: 2023-03-07
|
||||
# Developer: Hyperling
|
||||
# Purpose: Create a test user and some test data.
|
||||
|
||||
DIR=`dirname $0`
|
||||
PROG=`basename $0`
|
||||
if [[ $DIR == "." ]]; then
|
||||
DIR="`pwd`"
|
||||
echo $DIR/$PROG
|
||||
fi
|
||||
|
||||
## Create Test User ##
|
||||
|
||||
# insert into user values (-1, 'Hyperling', 'SuperSecretPassword')
|
||||
|
||||
## Create Entries ##
|
||||
|
||||
# Manually
|
||||
sqlite3 $DIR/db/main <<- EOF
|
||||
.headers on
|
||||
.echo on
|
||||
|
||||
delete from journal where user_id = -1;
|
||||
|
||||
insert into journal (user_id, cal_date, meal, food, caused_issue, comments)
|
||||
values (-1, '2023-03-22', 'Breakfast', 'Mango', '1', null);
|
||||
insert into journal (user_id, cal_date, meal, food, caused_issue, comments)
|
||||
values (-1, '2023-03-22', 'Lunch', 'Greasy restaurant food', '0', null);
|
||||
insert into journal (user_id, cal_date, meal, food, caused_issue, comments)
|
||||
values (-1, '2023-03-22', 'Snack', 'Rice and beans', '1', null);
|
||||
insert into journal (user_id, cal_date, meal, food, caused_issue, comments)
|
||||
values (-1, '2023-03-22', 'Dinner', 'Rice and beans', '1', null);
|
||||
|
||||
select * from journal where user_id = -1;
|
||||
EOF
|
||||
|
||||
## Via the API
|
||||
|
||||
# curl POST test_user 2023-03-07 "Mangoes and rice" FALSE "Yummy!"
|
||||
|
||||
## Remove any old test logs.
|
||||
rm -rfv $DIR/logs
|
11
tsconfig.json
Normal file
11
tsconfig.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "dist/",
|
||||
"noImplicitAny": true,
|
||||
"module": "es6",
|
||||
"target": "es5",
|
||||
"jsx": "react",
|
||||
"allowJs": true,
|
||||
"moduleResolution": "node",
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user