Complete Rewrite

This commit is contained in:
2024-09-14 11:04:06 -04:00
parent 926964f774
commit ec568c65b1
27 changed files with 2525 additions and 249 deletions

151
.gitignore vendored
View File

@@ -1,134 +1,21 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
.cache
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
node_modules
Backend/src/__pycache__
# Output
.output
.vercel
/.svelte-kit
/build
# OS
.DS_Store
Thumbs.db
# Env
.env
.env.*
!.env.example
!.env.test
# Vite
vite.config.js.timestamp-*
vite.config.ts.timestamp-*

View File

@@ -1,4 +0,0 @@
## Food Decisive Backend
This is the backend for the Food Decisive app. It is a RESTful API that serves the frontend of the app. The backend is written in Python using the Flask framework.

View File

@@ -1,5 +0,0 @@
MONGO_URI=""
PORT=80

Binary file not shown.

View File

@@ -1,31 +0,0 @@
import pymongo
class MongoDB:
def __init__(self, config):
self.myclient = pymongo.MongoClient(config['MONGO_URI'])
self.users = Users(self.myclient)
self.recipes = Recipes(self.myclient)
## User Schema
class Users:
def __init__(self, db):
self.db = db
self.users = self.db.myclient['users']
## Recipe Schema
class Recipe:
def __init__(self, name, ingredients, instructions, user):
self.name = name
self.ingredients = ingredients
self.instructions = instructions
self.rating = 0
self.user = user
class Recipes:
def __init__(self, db):
self.db = db
self.recipes = self.db.myclient['recipes']

View File

@@ -1,16 +0,0 @@
from flask import Flask
from dotenv import dotenv_values
from db import MongoDB
config = dotenv_values(".env")
app = Flask(__name__)
app.storage = MongoDB(config)
@app.route("/", methods=['GET'])
def home():
return "Hello World"
app.run(port=config['PORT'])

21
Client/.gitignore vendored
View File

@@ -1,21 +0,0 @@
node_modules
# Output
.output
.vercel
/.svelte-kit
/build
# OS
.DS_Store
Thumbs.db
# Env
.env
.env.*
!.env.example
!.env.test
# Vite
vite.config.js.timestamp-*
vite.config.ts.timestamp-*

View File

@@ -1,3 +0,0 @@
## Food Decisive Client-Side
This is the client-side for the Food Decisive app. It is a React app that serves the frontend of the app. The client-side is written in JavaScript using the Svelte framework.

View File

@@ -1,22 +0,0 @@
{
"name": "client",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"svelte": "^4.2.7",
"svelte-check": "^4.0.0",
"typescript": "^5.0.0",
"vite": "^5.0.3"
},
"type": "module"
}

View File

@@ -1,13 +0,0 @@
import adapter from '@sveltejs/adapter-auto';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter()
}
};
export default config;

View File

@@ -1,4 +1,38 @@
# Food Decisive
App for VTHacks
# create-svelte
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
## Creating a project
If you're seeing this, you've probably already done this step. Congrats!
```bash
# create a new project in the current directory
npm create svelte@latest
# create a new project in my-app
npm create svelte@latest my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
To create a production version of your app:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.

32
package.json Normal file
View File

@@ -0,0 +1,32 @@
{
"name": "project",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "vite build && node ./server/server.js",
"server": "node ./server/server.js",
"dev": "vite dev --host",
"build": "vite build"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"fs": "0.0.1-security",
"svelte": "^4.2.7",
"svelte-check": "^4.0.0",
"typescript": "^5.0.0",
"vite": "^5.0.3"
},
"type": "module",
"dependencies": {
"@sveltejs/adapter-node": "^5.2.2",
"body-parser": "^1.20.3",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.21.0",
"mongoose": "^8.6.2",
"ms": "^2.1.3"
}
}

2179
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

37
server/APIRoute.js Normal file
View File

@@ -0,0 +1,37 @@
import express from 'express';
import cookieParser from 'cookie-parser';
import bodyParser from 'body-parser';
export default class APIRoute {
constructor(path = '/') {
this.path = "/api" + path;
this.router = express.Router();
this.router.use(cookieParser());
this.router.use(bodyParser.json());
this.router.use(bodyParser.urlencoded({ extended: true }));
this.router.get("/", this.get);
this.router.post("/", this.post);
}
addSubRoute(name, method, callback) {
this.router[method](name, callback);
}
async get(req, res) {
res.send('GET request');
}
async post(req, res) {
res.send('POST request');
}
getPath() {
return this.path;
}
getRouter() {
return this.router;
}
}

44
server/APISession.js Normal file
View File

@@ -0,0 +1,44 @@
export default class APISession {
constructor() {
this.sessions = new Map();
}
generateSessionID() {
let id = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
return id;
}
createSession(id) {
if(this.sessions.get(id)) return false;
this.sessions.set(id, this.generateSessionID());
return this.sessions.get(id);
}
getSession(id) {
for (let [key, value] in this.sessions) {
if (key == id) return value;
}
return null;
}
setSession(id, value) {
if (!this.sessions.get(id)) return false;
this.sessions.set(id, value);
return true;
}
getSessionUser(sessionValue) {
for (let [key, value] of this.sessions) {
if (value == sessionValue) return key;
}
return null;
}
deleteSessionValue(id, key) {
if (!this.sessions.get(id)) return false;
this.sessions.delete(key);
return
}
}

75
server/server.js Normal file
View File

@@ -0,0 +1,75 @@
// @ts-nocheck
import { handler } from '../build/handler.js';
import dotenv from 'dotenv';
import http from 'http';
import express from 'express';
import cors from 'cors';
import fs from 'fs';
import ms from 'ms';
import Mongo from './storage/Mongo.js';
import APISession from './APISession.js';
dotenv.config();
const app = express();
const server = http.Server(app);
const MongoServer = new Mongo(process.env.MONGO_URI);
app.use(cors());
app.set("mongo", MongoServer);
app.set("session", new APISession());
async function loadFolder(filePath) {
let files = [];
fs.readdirSync(filePath).forEach(file => {
if (fs.lstatSync(`${filePath}/${file}`).isDirectory()) {
loadFolder(`${filePath}/${file}`);
} else {
files.push(`${filePath}/${file}`);
}
});
return files;
}
async function loadFiles(filePath) {
const file = await import(`../${filePath}`);
if (file.default) {
let route = new file.default();
app.use(route.path, route.getRouter());
console.log(`Loaded ${route.path}`);
}
}
try {
fs.readdirSync('./server/api').forEach(async(file) => {
if (fs.lstatSync(`./server/api/${file}`).isDirectory()) {
let files = await loadFolder(`./server/api/${file}`);
files.forEach(async(file) => {
await loadFiles(file);
});
} else {
await loadFiles(`./server/api/${file}`);
}
});
} catch (e) {
console.log(e);
} finally {
setTimeout(() => {
console.log('API loaded');
app.use(handler);
}, ms('1s'));
}
server.listen(process.env.PORT, () => {
console.log(`listening on port http://localhost:${process.env.PORT}`);
});
process.on('unhandledRejection', (reason, promise) => {
console.log('Unhandled Rejection at:', reason.stack || reason);
});
process.on('uncaughtException', (error) => {
console.log('Uncaught Exception thrown');
console.error(error);
});

18
server/storage/Mongo.js Normal file
View File

@@ -0,0 +1,18 @@
import mongoose from "mongoose";
import Users from "./collections/users.js";
export default class Mongo {
constructor(uri) {
this.connect(uri);
this.users = new Users();
}
async connect(uri) {
mongoose.set('strictQuery', true);
return mongoose.connect(uri).then(() => { console.log('MongoDB connected') });
}
async disconnect() {
return mongoose.disconnect();
}
}

View File

@@ -0,0 +1,72 @@
import mongoose from "mongoose";
const reqString = {
type: String,
required: true
}
const UserSchema = new mongoose.Schema({
id: reqString,
}, { timestamps: true });
export default class Users {
constructor() {
this.model = mongoose.model('users', UserSchema);
this.upsert = { upsert: true };
}
makeId(length) {
var result = [];
var characters = 'abcdefghijklmnopqrstuvwxyz012345678901234567890123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result.push(characters.charAt(Math.floor(Math.random() * charactersLength)));
}
return result.join('');
}
async create(user) {
if(await this.model.findOne({ username: user.username }) || await this.model.findOne({ email: user.email })) return null;
let Id = this.makeId(5);
await this.model.findOneAndUpdate({ id: Id }, {
id: Id,
}, this.upsert);
return await this.get(user.id);
}
async get(Id) {
let data = await this.model.findOne({ id: Id });
if(data) data.password = undefined;
return data;
}
async getByUsername(username) {
let data = await this.model.findOne({ username: username }) || await this.model.findOne({ email: username });
if(data) data.password = undefined;
return data;
}
async getAll(query) {
let data = await this.model.find(query);
data.forEach(user => {
user.password = undefined;
});
return data
}
async update(Id, data) {
if(!(await this.get(Id))) return null;
await this.model.findOneAndUpdate({ id: Id }, data, this.upsert);
return await this.get(Id);
}
async delete(Id) {
let result = await this.get(Id);
if(!result) return false;
await this.model.deleteOne({ id: Id })
return true;
}
}

View File

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

13
svelte.config.js Normal file
View File

@@ -0,0 +1,13 @@
import adapter from '@sveltejs/adapter-node';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
adapter: adapter()
},
csrf: {
checkOrigin: false,
}
};
export default config;