From e15d41e92c3184c7d77b9556ae3fc0100ab49be1 Mon Sep 17 00:00:00 2001 From: flalom Date: Sat, 28 Oct 2023 17:43:45 +0200 Subject: [PATCH 01/17] DB api fetching start --- backend/pyproject.toml | 2 ++ backend/src/clustering/__init__.py | 1 + backend/src/clustering/userClustering.py | 13 +++++++++++++ backend/src/{match => db}/__init__.py | 0 backend/src/db/dbFetcher.py | 24 ++++++++++++++++++++++++ 5 files changed, 40 insertions(+) create mode 100644 backend/src/clustering/__init__.py create mode 100644 backend/src/clustering/userClustering.py rename backend/src/{match => db}/__init__.py (100%) create mode 100644 backend/src/db/dbFetcher.py diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 457f7cf..1786c1e 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -9,6 +9,8 @@ readme = "README.md" python = "^3.9" pandas = "*" scikit-learn = "^1.3.2" +supabase = "^1.2.0" +fastapi = "^0.104.0" [tool.poetry.group.dev.dependencies] diff --git a/backend/src/clustering/__init__.py b/backend/src/clustering/__init__.py new file mode 100644 index 0000000..92343a5 --- /dev/null +++ b/backend/src/clustering/__init__.py @@ -0,0 +1 @@ +"""Subpackage related to use the distance matrix to cluster the users into groups.""" \ No newline at end of file diff --git a/backend/src/clustering/userClustering.py b/backend/src/clustering/userClustering.py new file mode 100644 index 0000000..5036d24 --- /dev/null +++ b/backend/src/clustering/userClustering.py @@ -0,0 +1,13 @@ +import numpy as np +from sklearn.cluster import DBSCAN +from scipy.spatial import distance + +def generateUserClusters(distanceMatrix): + """Generate clusters of users based on the distance matrix.""" + + # Apply DBSCAN on the distance matrix + dbscan = DBSCAN(metric='precomputed') + clusters = dbscan.fit_predict(distanceMatrix) + + # clusters now contains the cluster labels for each user + print(clusters) diff --git a/backend/src/match/__init__.py b/backend/src/db/__init__.py similarity index 100% rename from backend/src/match/__init__.py rename to backend/src/db/__init__.py diff --git a/backend/src/db/dbFetcher.py b/backend/src/db/dbFetcher.py new file mode 100644 index 0000000..746451a --- /dev/null +++ b/backend/src/db/dbFetcher.py @@ -0,0 +1,24 @@ +from fastapi import FastAPI, HTTPException +from supabase import create_client, Client + + +# Fetch data from the `users` table that correspond to a specific time range +async def fetch_users_by_time_range(start_time, end_time): + + app = FastAPI() + + # Replace these values with your Supabase project credentials + SUPABASE_URL = "https://your-supabase-url.supabase.co" + SUPABASE_ANON_KEY = "your-supabase-anon-key" + + supabase: Client = create_client(SUPABASE_URL, SUPABASE_ANON_KEY) + + @app.get("/items/{item_id}") + async def read_item(item_id: int): + response = await supabase.table("items").select().eq("id", item_id).execute() + item = response.get("data") + if item: + return item + raise HTTPException(status_code=404, detail="Item not found") + + From a058a50f1d940b49d3c76cd8832abfad9a067c24 Mon Sep 17 00:00:00 2001 From: Jonathan Wofford Date: Sat, 28 Oct 2023 18:32:52 +0200 Subject: [PATCH 02/17] added new branch --- frontend/src/Components/Scheduling.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/Components/Scheduling.js b/frontend/src/Components/Scheduling.js index c30989e..1f76c35 100644 --- a/frontend/src/Components/Scheduling.js +++ b/frontend/src/Components/Scheduling.js @@ -15,6 +15,9 @@ const Scheduling = (props) => { return slots; }; +const featureSoon = () => { + window.alert("Feature coming soon!"); +} return (
@@ -56,7 +59,7 @@ const Scheduling = (props) => {

Use default settings for a quick match.

- +

Adjust settings to find your perfect match.

From 65db8b42329fa748ff1058803f3aa65bb8e4f653 Mon Sep 17 00:00:00 2001 From: Jonathan Wofford Date: Sat, 28 Oct 2023 19:04:41 +0200 Subject: [PATCH 03/17] doing some styling on the scheduling div --- frontend/src/App.js | 6 +++--- frontend/src/Components/Scheduling.js | 10 +++++----- frontend/src/SCSS/Profile.css | 10 ++++++---- frontend/src/SCSS/navigation.css | 13 +++++++------ frontend/src/SCSS/scheduling.css | 14 +++++++++++++- 5 files changed, 34 insertions(+), 19 deletions(-) diff --git a/frontend/src/App.js b/frontend/src/App.js index ad5f5ac..a8db8b4 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -72,12 +72,12 @@ function App() { return ( <> - + }}>Test */} } /> )} - } path="/" /> + } path="/" /> ); diff --git a/frontend/src/Components/Scheduling.js b/frontend/src/Components/Scheduling.js index 1f76c35..3a73bdb 100644 --- a/frontend/src/Components/Scheduling.js +++ b/frontend/src/Components/Scheduling.js @@ -56,16 +56,16 @@ const featureSoon = () => {
-

Use default settings for a quick match.

+ {/*

Use default settings for a quick match.

*/}
-
+ {/*

Adjust settings to find your perfect match.

-
+
*/}
-
+ {/*
-
+
*/} ); }; diff --git a/frontend/src/SCSS/Profile.css b/frontend/src/SCSS/Profile.css index 93956fd..84a1348 100644 --- a/frontend/src/SCSS/Profile.css +++ b/frontend/src/SCSS/Profile.css @@ -7,20 +7,22 @@ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); text-align: center; } - + + .profile-container h2 { + color: black + } .profile-picture { width: 300px; height: 300px; border-radius: 50%; margin-bottom: 15px; } - + .profile-detail, .profile-interests { margin: 10px 0; } - + .profile-interests ul { list-style-type: none; padding: 0; } - \ No newline at end of file diff --git a/frontend/src/SCSS/navigation.css b/frontend/src/SCSS/navigation.css index 61163ed..90d81a6 100644 --- a/frontend/src/SCSS/navigation.css +++ b/frontend/src/SCSS/navigation.css @@ -6,9 +6,9 @@ box-shadow: 0px 0px 20px lightgrey; background-color: white; width: 6em; - padding-right: 25px; + /* padding-right: 25px; padding-top: 10px; - padding-bottom: 10px; + padding-bottom: 10px; */ } .hidden { @@ -35,6 +35,7 @@ cursor: pointer; display: flex; flex-direction: column; + } .drop-down-sign-out{ @@ -123,14 +124,14 @@ @media only screen and (max-width: 600px) { .profile-dropdown { position: absolute; - left: 65%; - top: 5%; + left: 60%; + top: 10%; border: 1px solid lightgrey; box-shadow: 0px 0px 20px lightgrey; background-color: white; width: 5em; - padding-top: 10px; - padding-bottom: 10px; + /* padding-top: 10px; + padding-bottom: 10px; */ } .drop-down-sign-out { margin-top: 10px; diff --git a/frontend/src/SCSS/scheduling.css b/frontend/src/SCSS/scheduling.css index bf9d94f..f872236 100644 --- a/frontend/src/SCSS/scheduling.css +++ b/frontend/src/SCSS/scheduling.css @@ -77,11 +77,15 @@ select, input[type="range"] { box-sizing: border-box; } + @media (max-width: 768px) { .scheduling-container { width: 100%; /* Adjusted for better mobile presentation */ padding-bottom: 20px; } + .scheduling-header { + text-align: center; + } .time-dropdown-guests-slider { flex-direction: column; @@ -116,7 +120,7 @@ select, input[type="range"] { } .quick-actions p, .advanced-actions p { - font-size: 14px; + font-size: 30px; color: #777; text-align: center; } @@ -142,3 +146,11 @@ select, input[type="range"] { .view-all-button:hover { background-color: #45a049; } + +.randomize-button { + height: 100px !important; + width: 250px !important; + font-size: 25px; + margin-top: 25px; + +} From 9f4061124f2a8bf9a59c60f1d5eefff369a4e122 Mon Sep 17 00:00:00 2001 From: Jonathan Wofford Date: Sat, 28 Oct 2023 19:13:52 +0200 Subject: [PATCH 04/17] adding auth --- frontend/src/App.js | 3 +++ frontend/src/Components/Login.js | 12 ++++++------ frontend/src/store/session.js | 18 ++++++++---------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/frontend/src/App.js b/frontend/src/App.js index a8db8b4..0397348 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -11,7 +11,10 @@ import { Route, Navigate, Routes } from 'react-router-dom'; // import Route and import Scheduling from './Components/Scheduling'; import{ supabase } from './supabaseclient'; + + function App() { + // const [isLoaded, setIsLoaded] = useState(false); // useEffect(() => { // dispatch(authenticate()).then(() => setIsLoaded(true)); diff --git a/frontend/src/Components/Login.js b/frontend/src/Components/Login.js index cc67095..a538650 100644 --- a/frontend/src/Components/Login.js +++ b/frontend/src/Components/Login.js @@ -4,16 +4,16 @@ import { login } from '../store/session'; import './../SCSS/Login.css'; function Login() { - const [username, setUsername] = useState(''); + const [email, setemail] = useState(''); const [password, setPassword] = useState(''); const dispatch = useDispatch(); + const handleSubmit = (e) => { e.preventDefault(); // Here you can send the username and password to your server - console.log('Username:', username, 'Password:', password); - dispatch(login(username, password)); + dispatch(login(email, password)); }; @@ -23,10 +23,10 @@ function Login() {
- +
diff --git a/frontend/src/store/session.js b/frontend/src/store/session.js index 09ec8b6..f0e02cb 100644 --- a/frontend/src/store/session.js +++ b/frontend/src/store/session.js @@ -1,6 +1,7 @@ // constants const SET_USER = "session/SET_USER"; const REMOVE_USER = "session/REMOVE_USER"; +const supabase = createClient("https://.supabase.co", "") const setUser = (user) => ({ type: SET_USER, @@ -30,16 +31,13 @@ export const authenticate = () => async (dispatch) => { }; export const login = (email, password) => async (dispatch) => { - const response = await fetch("/api/auth/login", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - email, - password, - }), - }); + const { data, error } = await supabase.auth.signInWithPassword({ + email: email, + password: password, + options: { + redirectTo: 'https//example.com/welcome' + } + }) if (response.ok) { const data = await response.json(); From 7dee7b88c4fae37afb7d5426011ed1abd9a15f16 Mon Sep 17 00:00:00 2001 From: Jonathan Wofford Date: Sat, 28 Oct 2023 20:04:54 +0200 Subject: [PATCH 05/17] user auth is working --- frontend/src/App.js | 28 +++++++++++---------------- frontend/src/Components/Login.js | 18 +++++++++++------ frontend/src/Components/Scheduling.js | 10 +++++----- frontend/src/store/session.js | 21 +++++++++++--------- 4 files changed, 40 insertions(+), 37 deletions(-) diff --git a/frontend/src/App.js b/frontend/src/App.js index 0397348..587e81c 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -44,11 +44,13 @@ function App() { } const user = useSelector(state => state.session.user); + console.log("LOGIN USER", user?.user?.id); + console.log("LOGIN", user); const Wrapper = () => { return (
- @@ -74,29 +76,21 @@ function App() { console.log(user); return ( <> - - {/* */} - - } path="/" /> - {user ? ( + {user ? ( //routes that will be available ONLY when user is logged in //add additional routes here - } path="/home" /> + } path="/home" /> ) : ( + // } path="/home" /> //will redirect to '/' from any url if no user is logged in //do not add additional routes here - } /> + <> + } /> + } path="/login" /> + )} - } path="/" /> ); diff --git a/frontend/src/Components/Login.js b/frontend/src/Components/Login.js index a538650..e59c2b7 100644 --- a/frontend/src/Components/Login.js +++ b/frontend/src/Components/Login.js @@ -2,23 +2,27 @@ import React, { useState } from 'react'; import {useDispatch} from 'react-redux'; import { login } from '../store/session'; import './../SCSS/Login.css'; +import { useNavigate } from "react-router-dom"; function Login() { - const [email, setemail] = useState(''); + const [email, setEmail] = useState(""); const [password, setPassword] = useState(''); const dispatch = useDispatch(); + const nav = useNavigate(); const handleSubmit = (e) => { e.preventDefault(); // Here you can send the username and password to your server - dispatch(login(email, password)); - + dispatch(login(email, password)) + .then(() => { + nav("/home"); + }) }; return ( -
+

Login

@@ -27,7 +31,7 @@ function Login() { setUsername(e.target.value)} + onChange={(e) => setEmail(e.target.value)} required /> @@ -44,7 +48,9 @@ function Login() {
- +
diff --git a/frontend/src/Components/Scheduling.js b/frontend/src/Components/Scheduling.js index 3a73bdb..1f76c35 100644 --- a/frontend/src/Components/Scheduling.js +++ b/frontend/src/Components/Scheduling.js @@ -56,16 +56,16 @@ const featureSoon = () => {
- {/*

Use default settings for a quick match.

*/} +

Use default settings for a quick match.

- {/*
+

Adjust settings to find your perfect match.

-
*/} +
- {/*
+
-
*/} +
); }; diff --git a/frontend/src/store/session.js b/frontend/src/store/session.js index f0e02cb..e5ccf60 100644 --- a/frontend/src/store/session.js +++ b/frontend/src/store/session.js @@ -1,7 +1,9 @@ +import { supabase } from "../supabaseclient"; + // constants const SET_USER = "session/SET_USER"; const REMOVE_USER = "session/REMOVE_USER"; -const supabase = createClient("https://.supabase.co", "") + const setUser = (user) => ({ type: SET_USER, @@ -31,23 +33,24 @@ export const authenticate = () => async (dispatch) => { }; export const login = (email, password) => async (dispatch) => { - const { data, error } = await supabase.auth.signInWithPassword({ + const response = await supabase.auth.signInWithPassword({ email: email, password: password, options: { redirectTo: 'https//example.com/welcome' } }) + console.log('RESPONSE', response) - if (response.ok) { - const data = await response.json(); + if (response.data.user) { + const data = response.data + console.log('DATA', data) dispatch(setUser(data)); return data; - } else if (response.status < 500) { - const data = await response.json(); - if (data.errors) { - return data.errors; - } + } else if (response.error) { + const data = response.error + console.log(data) + return data.errors; } else { return ["An error occurred. Please try again."]; } From 5c97fa25971c1a4291fed002415dd9ab77937c21 Mon Sep 17 00:00:00 2001 From: flalom Date: Sat, 28 Oct 2023 22:50:07 +0200 Subject: [PATCH 06/17] WIP fetching data function and one hot encoding of discrete --- backend/pyproject.toml | 1 + backend/src/db/dbFetcher.py | 46 ++++++++++++++++++++++++------------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 1786c1e..03a7419 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -11,6 +11,7 @@ pandas = "*" scikit-learn = "^1.3.2" supabase = "^1.2.0" fastapi = "^0.104.0" +python-dotenv = "^1.0.0" [tool.poetry.group.dev.dependencies] diff --git a/backend/src/db/dbFetcher.py b/backend/src/db/dbFetcher.py index 746451a..47e97cf 100644 --- a/backend/src/db/dbFetcher.py +++ b/backend/src/db/dbFetcher.py @@ -1,24 +1,38 @@ from fastapi import FastAPI, HTTPException from supabase import create_client, Client +from dotenv import load_dotenv +import numpy as np +import pandas as pd +import json +import os +# Load environment variables from .env file +load_dotenv() -# Fetch data from the `users` table that correspond to a specific time range -async def fetch_users_by_time_range(start_time, end_time): +# Get the credentials from the environment variables +SUPABASE_URL = os.environ.get('SUPABASE_URL') +SUPABASE_ANON_KEY = os.environ.get('SUPABASE_ANON_KEY') - app = FastAPI() +# Create a Supabase client +supabase: Client = create_client(SUPABASE_URL, SUPABASE_ANON_KEY) - # Replace these values with your Supabase project credentials - SUPABASE_URL = "https://your-supabase-url.supabase.co" - SUPABASE_ANON_KEY = "your-supabase-anon-key" +# Create a FastAPI app +app = FastAPI() - supabase: Client = create_client(SUPABASE_URL, SUPABASE_ANON_KEY) +@app.get("/encoded_data/{time_slot}/{location}") +async def get_encoded_data(time_slot: int, location: str): + # Fetch data + response = await supabase.table("items").select().eq("time_slot", time_slot).eq("location", location).execute() + data = response.get("data") + + if not data: + raise HTTPException(status_code=404, detail="Data not there") + + # Transform data + df = pd.DataFrame(data) + + # One-hot encode data + one_hot_encoded_df = pd.get_dummies(df, columns=['WIP']) # wip - replace with actual column names + #one_hot_encoded_df.to_dict(orient='records') - @app.get("/items/{item_id}") - async def read_item(item_id: int): - response = await supabase.table("items").select().eq("id", item_id).execute() - item = response.get("data") - if item: - return item - raise HTTPException(status_code=404, detail="Item not found") - - + return one_hot_encoded_df From 6f602a6b271053e006101cd481814f252410a0a4 Mon Sep 17 00:00:00 2001 From: tobiasschaeuble-eh Date: Sun, 29 Oct 2023 07:04:25 +0100 Subject: [PATCH 07/17] remove error component --- frontend/src/App.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/src/App.js b/frontend/src/App.js index 4983ffc..ad5f5ac 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -9,8 +9,6 @@ import Status from './Components/Status'; import {useSelector} from 'react-redux'; // import useSelector from react-redux import { Route, Navigate, Routes } from 'react-router-dom'; // import Route and Navigate from react-router-dom import Scheduling from './Components/Scheduling'; -import { Button } from 'react-scroll'; - import{ supabase } from './supabaseclient'; function App() { From f653e56aaa092f335f2edcc42d3a3a738c4ce925 Mon Sep 17 00:00:00 2001 From: tobiasschaeuble-eh Date: Sun, 29 Oct 2023 07:10:19 +0100 Subject: [PATCH 08/17] Valid times for planner --- frontend/src/Components/Scheduling.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/frontend/src/Components/Scheduling.js b/frontend/src/Components/Scheduling.js index a2e61dd..915580e 100644 --- a/frontend/src/Components/Scheduling.js +++ b/frontend/src/Components/Scheduling.js @@ -4,15 +4,16 @@ import "../SCSS/scheduling.css"; const Scheduling = (props) => { const generateTimeSlots = () => { let slots = []; - for (let i = 0; i < 24; i++) { - for (let j = 0; j < 60; j += 30) { - const hour = String(i).padStart(2, "12:00"); - const minute = String(j).padStart(2, "0"); - slots.push(`${hour}:${minute}`); - } + for (let i = 11; i <= 14; i++) { + for (let j = 0; j < 60; j += 30) { + if (i === 14 && j > 0) break; // Avoid adding 14:30 + const hour = String(i).padStart(2, '0'); + const minute = String(j).padStart(2, '0'); + slots.push(`${hour}:${minute}`); + } } return slots; - }; +}; return (
From 2cdd17f9f4d44e55ab656281d5082b36a4f69fe1 Mon Sep 17 00:00:00 2001 From: tobiasschaeuble-eh Date: Sun, 29 Oct 2023 07:25:24 +0100 Subject: [PATCH 09/17] nice --- frontend/src/Components/Scheduling.js | 30 +++++---- frontend/src/SCSS/scheduling.css | 89 +++++++++++++++++++++++---- 2 files changed, 96 insertions(+), 23 deletions(-) diff --git a/frontend/src/Components/Scheduling.js b/frontend/src/Components/Scheduling.js index 915580e..c30989e 100644 --- a/frontend/src/Components/Scheduling.js +++ b/frontend/src/Components/Scheduling.js @@ -16,11 +16,11 @@ const Scheduling = (props) => { }; return ( -
-
- Fancy having lunch together with interesting people? -
-
+
+
+ Fancy having lunch together with interesting people? +
+
Time Slot: @@ -49,13 +49,21 @@ const Scheduling = (props) => { {props.groupSize} Persons
-
-
- - - -
+
+
+
+ +

Use default settings for a quick match.

+
+
+ +

Adjust settings to find your perfect match.

+
+
+ +
+
); }; diff --git a/frontend/src/SCSS/scheduling.css b/frontend/src/SCSS/scheduling.css index c162c06..bf9d94f 100644 --- a/frontend/src/SCSS/scheduling.css +++ b/frontend/src/SCSS/scheduling.css @@ -1,8 +1,7 @@ .scheduling-container { - width: 100%; - height: 250px; - margin-top: 50px; - margin-bottom: 150px; + width: 80%; /* Adjusted for better desktop presentation */ + max-width: 1200px; /* Added for limiting width on very large screens */ + margin: 50px auto; /* Adjusted to center the container horizontally */ display: flex; flex-direction: column; align-items: center; @@ -13,7 +12,6 @@ margin-bottom: 50px; } - .time-dropdown-guests-slider { display: flex; gap: 30px; @@ -41,7 +39,7 @@ select { padding: 10px 15px; border-radius: 8px; border: 1px solid #ccc; - appearance: none; /* This removes the default OS styling */ + appearance: none; background-color: #fff; background-image: url('data:image/svg+xml;utf8,'); background-repeat: no-repeat; @@ -55,25 +53,92 @@ input[type="range"] { } select, input[type="range"] { - margin-left: 10px; /* added this line */ + margin-left: 10px; } - .slider { display: flex; align-items: center; gap: 20px; } - .button-div { width: 100%; display: flex; justify-content: center; - gap: 50px + gap: 50px; + flex-wrap: wrap; } -.button-div > button{ + +.button-div > button { width: 250px; height: 150px; - margin: 50px + margin: 50px; + box-sizing: border-box; +} + +@media (max-width: 768px) { + .scheduling-container { + width: 100%; /* Adjusted for better mobile presentation */ + padding-bottom: 20px; + } + + .time-dropdown-guests-slider { + flex-direction: column; + gap: 20px; + } + + .button-div { + flex-direction: column; + align-items: center; + } + + .button-div > button { + width: 100%; + height: auto; + padding: 15px; + margin: 10px 0; + } +} + +.actions-container { + display: flex; + justify-content: space-around; /* Adjusted for better spacing */ + width: 100%; + margin-top: 20px; +} + +.quick-actions, .advanced-actions { + display: flex; + flex-direction: column; + align-items: center; + width: 45%; /* Adjusted to fit better side by side */ +} + +.quick-actions p, .advanced-actions p { + font-size: 14px; + color: #777; + text-align: center; +} + +.view-all-container { + margin-top: 30px; + width: 100%; + display: flex; + justify-content: center; +} + +.view-all-button { + padding: 15px 25px; + font-size: 18px; + background-color: #4CAF50; + color: #fff; + border: none; + border-radius: 5px; + cursor: pointer; + transition: background-color 0.3s ease; +} + +.view-all-button:hover { + background-color: #45a049; } From 450ef16cef94bb02645026baccbf95e1ffe011c9 Mon Sep 17 00:00:00 2001 From: gordonkoehn Date: Sun, 29 Oct 2023 08:57:29 +0100 Subject: [PATCH 10/17] ranomizer basic --- backend/src/lunchheros/match/_randomize.py | 37 ++++++++++++++++++++++ backend/tests/match/test_randomize.py | 15 +++++++++ 2 files changed, 52 insertions(+) create mode 100644 backend/src/lunchheros/match/_randomize.py create mode 100644 backend/tests/match/test_randomize.py diff --git a/backend/src/lunchheros/match/_randomize.py b/backend/src/lunchheros/match/_randomize.py new file mode 100644 index 0000000..c8177a5 --- /dev/null +++ b/backend/src/lunchheros/match/_randomize.py @@ -0,0 +1,37 @@ +import random + + +def _randomize_groups(group_size: int, users: list[str]) -> list[list]: + """Randomize the groups of users. + + Makes groups of size ``group_size`` from the list of users ``users``. + If the number of users is not a multiple of ``group_size``, the remaining + users will be distributed randomly across the groups. + + Args: + group_size: size of the groups + users: list of users id + Returns: + A list of lists, each representing a group of users + """ + + # Shuffle the users randomly + random.shuffle(users) + + # Calculate the number of groups needed + num_groups = len(users) // group_size + + # Calculate the number of users that will be left alone + remaining_users = len(users) % group_size + + # Create the groups + groups = [] + for i in range(num_groups): + group = users[i * group_size : (i + 1) * group_size] + groups.append(group) + + # Distribute the remaining users across the groups + for i in range(remaining_users): + groups[i].append(users[num_groups * group_size + i]) + + return groups diff --git a/backend/tests/match/test_randomize.py b/backend/tests/match/test_randomize.py new file mode 100644 index 0000000..f2c1861 --- /dev/null +++ b/backend/tests/match/test_randomize.py @@ -0,0 +1,15 @@ +from lunchheros.match._randomize import _randomize_groups + + +def test_randomize_groups(): + """Test randomize groups.""" + groupsize = 4 + # make list of 21 users with string id + users = [str(i) for i in range(21)] + # randomize groups + groups = _randomize_groups(groupsize, users) + print(groups) + # check that all groups are at least 2 users + assert all(len(group) >= 2 for group in groups) + # check that all groups are at most 4 users + assert all(len(group) <= groupsize + groupsize for group in groups) From ab87b17c4af54e40a5c72d45459d5e6d7956981a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20N=C3=BC=C3=9Flein?= <65328894+Philnue@users.noreply.github.com> Date: Sun, 29 Oct 2023 10:03:28 +0100 Subject: [PATCH 11/17] Updated Api for button trigger --- backend/__pycache__/main.cpython-311.pyc | Bin 1439 -> 1967 bytes backend/main.py | 12 +++++- backend/src/lunchheros/db/dbFetcher.py | 38 +++++------------- .../__pycache__/userFunctions.cpython-311.pyc | Bin 1086 -> 1115 bytes backend/src/routes/users/userFunctions.py | 5 +-- 5 files changed, 23 insertions(+), 32 deletions(-) diff --git a/backend/__pycache__/main.cpython-311.pyc b/backend/__pycache__/main.cpython-311.pyc index 369adb70ab3293b5e9f746e0aaa8fb068938a0ec..1efd25ea4177b0a83a7fc6e2bb6f57612f994da8 100644 GIT binary patch delta 913 zcmZ8e&1(}u6rYdXbdxmMlv*2Xv6ZHc3z}YwND~Gr#xoo8P{-mHujHKW8#21nbGf zJg?D>Y<}?`M(90ah+!WExPq~|6Q2aMLiL^cMqpOVAW=zZZ1@9#Rk8Hl^piodlEjE0 zZfyhajw08qlH#e4>1YoRZ|oM#!6WduU}g@1gIH=C-rs?*w^(`|o#M$JW-lT(cq%)? z?PbEU>&EFCWBXAwxWyVJhr1- zdFY*p5|wl+F{siR6|j()wq~_*5i61 z#vtq+wG9C6e}5LDZ*WvVPqKqx| zzzt}}Nu^qrHY!IJ!K|U5_W0(*J-e`P7uIh7Fp_VJFU#xYwQ@IsvSXW%I_a5?F(a<2 z|0p}TIJfM|&~4RA{Sio^6vtyycqPBx@K#p1Xvz{>g1x{)51=q0Bf4)~SXBe)sU7Ik zhymrY6a{r#t(d|%g_@Y2g4P;S8Hz7RCjgE^c~V1jn)YO%a(sj2^qS FrvK&;)-nJ9 delta 425 zcmZ8cJxc>Y5Z&3Y#EZG0@gs;I5z}1oC#Z!*z(xzZYr?^v64)bQFZl=BH|!~M8PhkmW~iEKm^QJ_fz zAtW@U;5gMR;UUj+rbQw`0fds6PtbAan&c76SY8!|&((k^J^?J@`3WU1$iK(M-^asI zL(KicSwPHu-HlW` z(z-oJW0RT{6f5?fZ9&x*d1sv?4`?P`^+=f-(v%|9(QhyLs#rs^WT$+mP{r&xC|NGI zm78XqH!GY)X+P?9jBt{45{r7hjGf1QrZBfKL@`bD zQw(C!b+jEsyo7_={-q7Q5g0;!A*JRevX Q8Iu`5Fd&f}lVw>H0XjoD2><{9 delta 180 zcmcc3v5$jyIWI340}v!Q*`}sWrZBfKL@^HNY2kKNX)CWg3y_%#T$2AV`Ai<+|OL%l>{{F12ZEd;|&Jw3#jM=8-svm f1J4H*M#f~u4-7~o8v~;bx?+~e4lH7m16a5Lb-gZY diff --git a/backend/src/routes/users/userFunctions.py b/backend/src/routes/users/userFunctions.py index c2af593..d035f72 100644 --- a/backend/src/routes/users/userFunctions.py +++ b/backend/src/routes/users/userFunctions.py @@ -1,13 +1,12 @@ from supabase_client import supabase_client -users_select = "*, company:companies(*)" +users_select = "*, company:companies(*), users_interests(*, interest(*, category(*))), age_range(*)" def getUserWithId(userId): return supabase_client.table("users").select(users_select).eq("id", userId).single().execute() -from supabase_client import supabase_client def getAllUsers(): return supabase_client.table("users").select(users_select).execute() - \ No newline at end of file + From f430f0856375ba186b698a847707a4a881e3211e Mon Sep 17 00:00:00 2001 From: lucca93 Date: Sat, 28 Oct 2023 23:35:46 +0200 Subject: [PATCH 12/17] Dockerfile and nginx.conf Frontend: Added react-scroll in package.json for Docker --- docker/Dockerfile | 58 +++++++++++++++++++++++++++++++++++++++++ docker/README.md | 60 +++++++++++++++++++++++++++++++++++++++++++ docker/gunicorn.conf | 2 ++ docker/nginx.conf | 15 +++++++++++ frontend/package.json | 1 + 5 files changed, 136 insertions(+) create mode 100644 docker/Dockerfile create mode 100644 docker/README.md create mode 100644 docker/gunicorn.conf create mode 100644 docker/nginx.conf diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..3233e16 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,58 @@ +# --- Backend Build Stage --- +FROM python:3.9-slim as backend + +WORKDIR /app + +# Install Poetry +RUN pip install poetry + +# Copy the Poetry configuration and lock files +COPY backend/pyproject.toml backend/poetry.lock /app/ + +# Install dependencies without creating a virtual environment +RUN poetry config virtualenvs.create false \ + && poetry install --no-dev --no-interaction --no-ansi + +# Install Gunicorn +RUN pip install gunicorn + +# Copy the backend source code into the image +COPY backend /app/ + +# --- Frontend Build Stage --- +FROM node:14 as frontend + +WORKDIR /app + +# Copy the frontend package configuration files +COPY frontend/package*.json /app/ + +# Install dependencies +RUN npm install + +# Copy the frontend source code into the image +COPY frontend /app/ + +# Build the frontend +RUN npm run build + +# --- Nginx Stage --- +FROM nginx:alpine + +# Copy the built frontend files to the Nginx server +COPY --from=frontend /app/build /usr/share/nginx/html + +# Copy the backend app to a directory served by Gunicorn +COPY --from=backend /app /app + +# Set up Gunicorn to serve the backend app +COPY docker/gunicorn.conf /etc/gunicorn/gunicorn.conf + +# Set up Nginx to proxy requests to Gunicorn +COPY docker/nginx.conf /etc/nginx/conf.d/default.conf + +# Expose the necessary ports +EXPOSE 80 + +# Start Gunicorn and Nginx +CMD ["sh", "-c", "gunicorn -c /etc/gunicorn/gunicorn.conf app:app & nginx -g 'daemon off;'"] diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..97a0431 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,60 @@ +# LunchHeroes Docker Configuration + +This Docker setup is designed to build the Docker image for the LunchHeroes application, which can then be pushed to a Docker registry and deployed on a server. + + +## Preliminary Steps + +1. **Building the Docker Image** + To build the Docker image, navigate to the directory containing the Dockerfile and run the following command: + ```bash + docker push lucca93/lunchheroes:latest + ``` + +2. **Pushing Docker Image:** + - After building the Docker image, push it to your Docker registry using the following command: + ```bash + docker push lucca93/lunchheroes:latest + ``` + + +**Server Hosting:** + - The server is hosted on [Flow Swiss](https://my.flow.swiss/). + +## File Descriptions + +### Dockerfile + +The Dockerfile orchestrates the build process for both the frontend and backend of the LunchHeroes application. Here's a brief overview of each stage in the Dockerfile: + +- **Backend Build Stage:** + - Uses the `python:3.9-slim` base image. + - Installs Poetry for dependency management. + - Copies and installs the backend dependencies using Poetry. + - Installs Gunicorn as the WSGI HTTP server to serve the backend application. + - Copies the backend source code into the image. + +- **Frontend Build Stage:** + - Uses the `node:14` base image. + - Copies and installs the frontend dependencies using npm. + - Copies the frontend source code into the image. + - Builds the frontend assets. + +- **Nginx Stage:** + - Uses the `nginx:alpine` base image. + - Copies the built frontend files to the Nginx server. + - Copies the backend app to a directory served by Gunicorn. + - Sets up Gunicorn to serve the backend app. + - Sets up Nginx to proxy requests to Gunicorn for the `/api` endpoint. + - Exposes port 80. + - Starts Gunicorn and Nginx. + +### gunicorn.conf + +This file contains the Gunicorn configuration. Gunicorn is set up to bind to `0.0.0.0:8000` and uses 3 worker processes. + +### nginx.conf + +This file contains the Nginx configuration. Nginx is set up to serve the static frontend files and to proxy requests to the `/api` endpoint to Gunicorn. + + diff --git a/docker/gunicorn.conf b/docker/gunicorn.conf new file mode 100644 index 0000000..373ea0d --- /dev/null +++ b/docker/gunicorn.conf @@ -0,0 +1,2 @@ +bind = "0.0.0.0:8000" +workers = 3 diff --git a/docker/nginx.conf b/docker/nginx.conf new file mode 100644 index 0000000..12ef0ad --- /dev/null +++ b/docker/nginx.conf @@ -0,0 +1,15 @@ +server { + listen 80; + + location / { + root /usr/share/nginx/html; + try_files $uri /index.html; + } + + location /api { + proxy_pass http://localhost:8000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +} diff --git a/frontend/package.json b/frontend/package.json index 522c1d5..793c474 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "react-scroll": "^1.8.3", "@supabase/supabase-js": "^2.38.4", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", From 44f45258fe506df7eaf6bc6f39bd51e002e0cc02 Mon Sep 17 00:00:00 2001 From: gordonkoehn Date: Sun, 29 Oct 2023 10:39:13 +0100 Subject: [PATCH 13/17] parae Json --- backend/src/lunchheros/db/dbFetcher.py | 12 +++++++++++ backend/src/lunchheros/match/_randomize.py | 3 +++ backend/tests/match/test_randomize.py | 25 ++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/backend/src/lunchheros/db/dbFetcher.py b/backend/src/lunchheros/db/dbFetcher.py index 407206f..429af96 100644 --- a/backend/src/lunchheros/db/dbFetcher.py +++ b/backend/src/lunchheros/db/dbFetcher.py @@ -18,3 +18,15 @@ async def get_encoded_data(time_slot: int, location: str, data): #one_hot_encoded_df.to_dict(orient='records') #return one_hot_encoded_df + + +def parse_user_id_tolist(test_data): + data = json.loads(test_data) + + # Extract the id values into a python list + ids = [x['id'] for x in data] + + # Convert the python list to a numpy array + numpy_array = np.array(ids).tolist() + + return numpy_array diff --git a/backend/src/lunchheros/match/_randomize.py b/backend/src/lunchheros/match/_randomize.py index c8177a5..c1a0750 100644 --- a/backend/src/lunchheros/match/_randomize.py +++ b/backend/src/lunchheros/match/_randomize.py @@ -35,3 +35,6 @@ def _randomize_groups(group_size: int, users: list[str]) -> list[list]: groups[i].append(users[num_groups * group_size + i]) return groups + + + diff --git a/backend/tests/match/test_randomize.py b/backend/tests/match/test_randomize.py index f2c1861..e3236e7 100644 --- a/backend/tests/match/test_randomize.py +++ b/backend/tests/match/test_randomize.py @@ -1,5 +1,7 @@ from lunchheros.match._randomize import _randomize_groups +import json +import numpy as np def test_randomize_groups(): """Test randomize groups.""" @@ -13,3 +15,26 @@ def test_randomize_groups(): assert all(len(group) >= 2 for group in groups) # check that all groups are at most 4 users assert all(len(group) <= groupsize + groupsize for group in groups) + + + + +test_data = '[{"id":"b994511a-4b7c-4d52-bb26-baeffde1df7d"},{"id":"6ea2070c-18e4-4946-83a4-c41584b3eb9a"},{"id":"f60d3486-e6da-45d9-8a68-b39634c2c1c2"},{"id":"89bce073-f759-4290-87dc-87c63a54c553"},{"id":"456732ea-1a2c-42ed-8d9a-4ff83cc9391d"},{"id":"4404a8a1-3429-45f0-b516-2656cfd96643"},{"id":"08e11522-0d52-4014-9c47-d0b4f27b6716"},{"id":"6923fe00-70dd-4bf6-8c7a-7a15c6f8482e"},{"id":"797ee2cb-5c90-4a09-b15d-f4902193b618"},{"id":"aa3e50f0-091a-458f-a62a-caa586b77751"},{"id":"cfc5a3ec-9fdb-4d8a-b380-4737f7e4c5ed"},{"id":"460c2346-459b-4eaa-b821-b6778be53b14"},{"id":"3738d56c-615c-4129-b389-34b75e788580"},{"id":"d50d37d3-f718-40ea-b3b3-c54593b9b048"},{"id":"5e933bdf-29ca-45fb-8f45-3e4c4805ca60"},{"id":"683bcf3c-f855-4164-9057-a5266fb685e3"},{"id":"85e9d50a-a110-44c7-a512-9c6e285fde09"},{"id":"dd1b225d-4320-4aa2-8873-c25ca5307fbf"},{"id":"5423ae0b-0535-443b-89ab-9defd6ee6eda"},{"id":"ad53c0f5-6a93-4904-bfec-22bf7da98ef4"},{"id":"3dc8e3eb-be7c-4e1f-a92d-7ce3b3ee42c3"},{"id":"691888e2-536e-4183-ae98-1d03e643eeb4"},{"id":"a8e24543-0251-41d7-9eff-dbb3b2690d23"},{"id":"da7762a0-5172-4d6f-ab2f-9eb7a953bd9e"},{"id":"a9a3c0b6-df0a-4b39-b613-582703201145"},{"id":"25d411a2-5ac9-445f-a33f-25ece3dde23b"},{"id":"1784f97e-9f3b-4059-a8b4-7c23c3c8897d"},{"id":"7819f098-6772-4aa8-895e-d193199514c8"},{"id":"1df69d95-dbf5-4e68-a102-01974ea7939c"},{"id":"abb3dead-c9e4-4dbd-922a-c7fbe8f448a8"},{"id":"654a36f8-7b36-4ec1-a02e-e45c3673442e"},{"id":"9edeb3f4-ee7e-417e-aaee-d7a40ed0f24a"},{"id":"3f1cec4e-b1ea-4d0f-91d6-f3ff964b2bf1"},{"id":"ce821535-9969-4a93-9b8d-a80a6242f998"},{"id":"f154a6c9-e1b0-4b67-97ab-d65c69ebed69"},{"id":"04b91fd2-78cf-4779-bd7f-0c0bca1c5187"},{"id":"447e63ba-a69b-4b0a-9bfd-6c9d8b19026a"},{"id":"2229ba43-1c63-425e-b157-1368399b2d73"},{"id":"ae4b46d4-984d-44ed-9e3c-cf8823bb0ebf"},{"id":"c9339894-43fb-45e6-b7ba-f527eeb4a3ea"},{"id":"7c047b21-be3c-427e-92c2-82b7fd7459d3"},{"id":"ee3ed5cf-718d-4d34-bfee-b54057870f7e"},{"id":"787dd532-a1c5-4d15-a371-35e6b5e6a169"},{"id":"9bb0689f-4018-40af-9224-1d2595e75801"},{"id":"bb8bd4e1-dce6-46d9-b9b1-20b46a0bfd68"},{"id":"ae93a1ab-921c-4062-95d9-fcd11357a4b6"},{"id":"4837001a-73b0-4b18-bfda-caccee8aef7f"},{"id":"d007dc20-8bae-4c58-b634-ec42e334e0b6"},{"id":"c6e4f2c4-5ed2-4d8f-9075-36b3f77abc37"},{"id":"dc1b7985-aa01-4087-9b35-f6fa6dc6e2b0"},{"id":"00b1fc3d-8e79-4558-af44-ec8d0a6bb3c2"},{"id":"50c17ac7-5e41-4476-b8ba-f59da66885b1"},{"id":"65980da4-879c-401d-9be0-71209c92c62b"},{"id":"bc74a884-7603-4824-be06-6c82091eb24e"},{"id":"a9670953-5906-4190-848c-5a27cdaa12a3"},{"id":"6a23c795-3a9f-4c81-80f8-92ff3088ae36"},{"id":"d2a3fcef-2518-47cd-b038-5bb16599fca9"},{"id":"c549f2c8-862c-4f0a-9302-7784e8ce6608"},{"id":"c7d6a357-368c-454b-a0ef-fcf2da5442b7"},{"id":"dca40f83-27a2-456e-855e-8f5b5df6744e"},{"id":"c93e381b-81a2-485d-9337-5ccb3d33da4c"},{"id":"6bc16283-2b9d-4196-82f1-dafd05805388"},{"id":"541fa596-b1d1-4da2-bb50-26950006c484"},{"id":"7ce5d11c-c44f-4aaf-878e-2e4d14e68339"},{"id":"e77ee698-bdf4-4e62-9dcf-23b10df1bec1"},{"id":"9507a229-592b-4c87-ae04-52e25d22a6bd"},{"id":"fc4ae092-ef73-4cc3-840b-70e9940d33f1"},{"id":"ae29079c-2bfc-4ce3-a924-339b88c59bbf"},{"id":"6e591ada-490e-4174-9ab9-dc4879632c27"},{"id":"e7467801-c20c-4359-b99f-d5d132e51fc7"},{"id":"edc783c5-531f-4f21-a9cc-574451847065"},{"id":"60a7563a-b5b1-4924-936f-9c8deb78cd9d"},{"id":"1cdbc0a9-eba0-4926-b94b-99164328dba3"},{"id":"81be34d5-e71b-456e-a913-21fece836215"},{"id":"48add589-f329-49e9-a151-fae9d44e08f4"},{"id":"dca5539f-c660-488e-99cf-5f9258c6c84e"},{"id":"78888bef-a3e8-4ee1-a54d-c8bd14d30898"},{"id":"aba32f5e-d5a3-4466-bcf6-77eda1de5214"},{"id":"55251bbf-21c0-4f62-a560-ca12f8235342"},{"id":"790de1d5-df0a-4570-943c-f0089d561bc3"},{"id":"90864c9f-612b-457b-8e42-8afb46f3f922"},{"id":"8915ac2c-c740-42df-8fa1-0c1d132bb92e"},{"id":"f48d9896-c80b-4745-abc3-50acfde0a63c"},{"id":"b1434b1c-1a6c-441d-9812-90bdaee1215f"},{"id":"5596fbd9-f33a-4fb0-b844-e6a979a35ac7"},{"id":"bdcf15c4-b164-49ed-a42e-2d6be5fba168"},{"id":"0a1f949e-5d8e-4080-9936-de0f94e26271"},{"id":"57aa5b15-4c93-49c7-8e4c-5c0982353749"},{"id":"8d98509f-464a-4c26-9142-f5903c260a51"},{"id":"5fce6888-9570-4f7b-90c5-be2e9f3f7035"},{"id":"e6940d4a-a287-4dc9-b293-60cabc3b4655"},{"id":"666137b1-ffa8-4612-8e99-08e93691e33b"},{"id":"180d1e45-d8ab-4679-a260-037416c8b9ea"},{"id":"7d11ea4e-f72d-4bf5-a71f-57b373435fd1"},{"id":"81940ce9-34c7-4288-b343-99ea4464493c"},{"id":"3fb80679-0120-4383-8047-e3e8da12d69d"},{"id":"e30ffdaf-2467-42ce-a703-034a478b0417"},{"id":"06cbb2ea-96e0-4896-a425-b098957af37a"},{"id":"cb7e5907-68e7-44bd-95c0-06ccebc075db"},{"id":"bbbbaf3c-1d57-4e11-bf88-9bf92d374b97"},{"id":"bf7c7244-ff86-470c-ba95-07f1e21c9682"},{"id":"4117890c-bdd9-487c-9921-d7a5c9d9b08d"},{"id":"5925b106-1578-45a9-bb30-7fafb37cccdb"},{"id":"00d4050b-614b-4be8-aa16-cab95f6e7dca"},{"id":"4938a261-8083-44d2-955f-c00856f8eb6d"},{"id":"798bdf20-1614-4026-9235-ab10ba228dae"},{"id":"b932c46d-3db7-4cd9-8007-6db3cf2b923b"},{"id":"2e9db169-2094-417e-a775-c8a75790c458"},{"id":"fb16e78e-5ccb-4635-b355-a01f0834389c"},{"id":"9a7ae5aa-b788-49fd-8894-9f899f2a2587"},{"id":"3c3a5aca-6c0e-4e9d-90cb-557fef1256c1"},{"id":"31d574de-869d-4098-be2b-addbfdacebcb"},{"id":"bbaa570b-295b-4bbd-bfd4-02e0b754419e"},{"id":"1e7d409b-03e0-46ef-bdc3-cb55807c10a4"},{"id":"46da386a-c562-4eea-9ae9-c6f87700dbc3"},{"id":"5c5ac49c-a9e9-4fbb-84d1-c5e956f30781"},{"id":"7ddd95e3-3a77-4b61-9d0a-3ffaa1c5a95a"},{"id":"36ad540a-b857-433a-8d07-4087e4d0fe4a"},{"id":"ea88696e-7e9b-49e9-8d65-ace6084425d7"},{"id":"05f6a875-9cc5-4185-8352-0afab880ff4d"},{"id":"6fdb38c9-be3c-44df-9a7a-3f73413842b3"},{"id":"f3313ebc-7b1d-4691-9e65-5ff4e549210a"},{"id":"92cdf84d-485b-4bc6-af29-e9853d20ff5d"},{"id":"878fd4ae-c15c-4325-90f5-4674d04c5455"},{"id":"36e6896d-1814-4348-94f8-a83282d1503b"},{"id":"d6fdf1c7-1333-4382-bac9-4a8a37608b02"},{"id":"37c19c16-e97c-4276-8bf9-97ef7c29d747"}]' + + +def test_randomize_with_real(): + """Test randomize groups.""" + # read in the test data + # Load the JSON data into a python list of dictionaries + data = json.loads(test_data) + + # Extract the id values into a python list + ids = [x['id'] for x in data] + + # Convert the python list to a numpy array + numpy_array = np.array(ids) + print(numpy_array) + group_size = 4 + # randomize groups + groups = _randomize_groups(group_size, numpy_array.tolist()) + print(groups) \ No newline at end of file From 38f5a446ae284ee41d298f5a66cc7ff379c4c112 Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 29 Oct 2023 10:47:41 +0100 Subject: [PATCH 14/17] Add Query list data --- backend/main.py | 6 +++--- backend/src/routes/users/userFunctions.py | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/backend/main.py b/backend/main.py index 3fcf759..c4ba8fa 100644 --- a/backend/main.py +++ b/backend/main.py @@ -2,7 +2,7 @@ from fastapi.encoders import jsonable_encoder from src.lunchheros.db.dbFetcher import get_encoded_data -from src.routes.users.userFunctions import getAllUsers, getUserWithId +from src.routes.users.userFunctions import getAllQueryListData, getAllUsers, getUserWithId from fastapi import FastAPI from supabase_client import supabase_client @@ -27,7 +27,7 @@ def load_current_user(userId): @app.get("/button_trigger/{userId}") def load_current_user(userId: str): userData = getUserWithId(userId) - print("asdas") + queryList = getAllQueryListData() #test = get_encoded_data(1,1,userData) - return { "currentUser" : userData} \ No newline at end of file + return { "currentUser" : userData, "query": queryList} \ No newline at end of file diff --git a/backend/src/routes/users/userFunctions.py b/backend/src/routes/users/userFunctions.py index d035f72..48006f4 100644 --- a/backend/src/routes/users/userFunctions.py +++ b/backend/src/routes/users/userFunctions.py @@ -10,3 +10,7 @@ def getUserWithId(userId): def getAllUsers(): return supabase_client.table("users").select(users_select).execute() + +def getAllQueryListData(): + return supabase_client.table("waiting_query").select(f"*, user({users_select}), time_range(*), company(*), age_range(*)").execute() + From 32d238309448f4f4c1d4dd04b32f4148e696ccdb Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 29 Oct 2023 10:47:51 +0100 Subject: [PATCH 15/17] Add query data AD --- backend/__pycache__/main.cpython-311.pyc | Bin 1967 -> 2018 bytes .../supabase_client.cpython-311.pyc | Bin 677 -> 677 bytes .../__pycache__/userFunctions.cpython-311.pyc | Bin 1115 -> 1508 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/backend/__pycache__/main.cpython-311.pyc b/backend/__pycache__/main.cpython-311.pyc index 1efd25ea4177b0a83a7fc6e2bb6f57612f994da8..d14048f66df0d2236cb888729fbeabdfbaaac184 100644 GIT binary patch delta 616 zcmZ`#&1(}u6rVTyk=?}YMB1bVw?XK}Hj2_i@z6>^@L*6XqA2X8UAo&6*w8q;5rjhX z5A+b`U=JPyztA4^?#YWFBD9#(fEUr5hjA{h~>+!+8 z!15034}mrIrxpwXiydAr!vvJYDpY`pJ1}20Bu};}G-GVI|!+m;Pv6q`v6Qy+erW->xxlNcf4O;7ytCGBX?IyzkFq@Kwz-4Ct^#R9-L5p$IC%x%Y6$2k zjV$NSh!)Wk`|h0YY{tDbS>hN3N12@weS6Li_sM^^cw@ghySTeHA{H$Eg>MF-jUfah J`p>g=`vn(Po5lbD delta 639 zcmZut&ui2`6rMN9WV2h7DBHT#U9{4)F$f~1N9jqyUZN<7?4^v!v@B%XbtVg?2(HkB z*JUmXUId{cMf?K`o3qjpEN5v^R@gR6`vr@E z2l5arBe`TfJx|oCYBkhLfPy(**J3~4qS+eF^R>QUT<}@>&6KOg!kzbrw7o$-+K?I`T@X11W;Q+!3 J{;O?regFy^ngsv= diff --git a/backend/__pycache__/supabase_client.cpython-311.pyc b/backend/__pycache__/supabase_client.cpython-311.pyc index 572bd0524c2a5610a43072c8b662208fdc753ebe..c70a168eb295c52939b4dedf444b9bae7c9af0f8 100644 GIT binary patch delta 20 acmZ3=x|EfBIWI340}w1#w%f=(iwOWQJOqgV delta 20 acmZ3=x|EfBIWI340}$jY+iv8Z#RLE@uLMv4 diff --git a/backend/src/routes/users/__pycache__/userFunctions.cpython-311.pyc b/backend/src/routes/users/__pycache__/userFunctions.cpython-311.pyc index ea4a3a39ea873ebb551343498509d516a8262f55..28fa595f4d0ea518a79860182878ecb240dc0a9a 100644 GIT binary patch delta 420 zcmcc3@r0XiIWI340}vFd*`+ElP2`hc)R?HQ%+(T|;(apmMNW)nt{ z$=%F$;>jT8Fu)3AFaz=Dw#jFh97R%?O4wjh3=FdwQkds5PnKs?ncUAPSkK~ji?=*6 zvm`SwJ-)CswWzX+LrX`Yv^cd$qe@FtN1-G$H#NQ}F)uw;1H?_v&n-yIs|2$X(-AU7 zLO>gegh7M=h~NVfw}jJEOB{1@0zt<5WEPjWB$gx=i34Rovc(=iqM@GQE|2sT9>oRv z7kP}X@EBd^vAo1%dBLjoXbg~mpo=_pS9t2aGcfSFGkpS+AAzJN(-$!Lfq{Y5lL>6A zpC)S&$lpbrAc7x6h=2%?m1u7J#bJ}1pHiB`n`&1i0hDG0;^M@~EG+Iy9E^;fOdlAq HlVE!QGS*?G delta 129 zcmaFDeVc=CIWI340}yb^+NG8;PUMqdRGO%+%o5C?$+j_sotaT{atyNxqwwU3%y!m( znk+@kK($4jAc7x62!jYA5Fr2}_<+PO4x8Nkl+v73yCM-Fml24I{U=wmx(hHcGI}w7 I0Fz+l02}NU@&Et; From d601ed9ec4140e0811d8d3172fe3bf7bd1e51970 Mon Sep 17 00:00:00 2001 From: tobiasschaeuble-eh Date: Sun, 29 Oct 2023 10:57:44 +0100 Subject: [PATCH 16/17] Push Tayyab css UI Changes --- frontend/src/Components/ProfileButton.js | 12 +- frontend/src/Components/Scheduling.js | 141 +++++++------ frontend/src/SCSS/Profile.css | 51 +++-- frontend/src/SCSS/navigation.css | 258 +++++++++++------------ frontend/src/SCSS/scheduling.css | 136 +++++++----- 5 files changed, 307 insertions(+), 291 deletions(-) diff --git a/frontend/src/Components/ProfileButton.js b/frontend/src/Components/ProfileButton.js index 3d51673..68b475e 100644 --- a/frontend/src/Components/ProfileButton.js +++ b/frontend/src/Components/ProfileButton.js @@ -1,22 +1,17 @@ import React, { useState, useEffect, useRef } from "react"; - import { logout } from "../store/session"; import { useNavigate } from "react-router-dom"; import "../SCSS/navigation.css"; - function ProfileButton({ user }) { const [showMenu, setShowMenu] = useState(false); const ulRef = useRef(); const navigate= useNavigate() - const openMenu = () => { if (showMenu) return; setShowMenu(true); }; - useEffect(() => { if (!showMenu) return; - const closeMenu = (e) => { if (!ulRef.current.contains(e.target)) { setShowMenu(false); @@ -25,21 +20,17 @@ function ProfileButton({ user }) { document.addEventListener("click", closeMenu); return () => document.removeEventListener("click", closeMenu); }, [showMenu]); - const handleLogout = (e) => { e.preventDefault(); logout(); navigate("/"); }; - const navUserProfile = (e) => { e.preventDefault(); navigate('/profile') } - const ulClassName = "profile-dropdown" + (showMenu ? "" : " hidden"); const closeMenu = () => setShowMenu(false); - return ( <> +

Use default settings for a quick match.

+
+
+ +

Adjust settings to find your perfect match.

+
+
+
+ +
-
-
- -

Use default settings for a quick match.

-
-
- -

Adjust settings to find your perfect match.

-
-
-
- -
- - ); + ); }; - -export default Scheduling; +export default Scheduling; \ No newline at end of file diff --git a/frontend/src/SCSS/Profile.css b/frontend/src/SCSS/Profile.css index 84a1348..9048283 100644 --- a/frontend/src/SCSS/Profile.css +++ b/frontend/src/SCSS/Profile.css @@ -1,28 +1,25 @@ .profile-container { - border: 1px solid #e0e0e0; - padding: 20px; - border-radius: 10px; - max-width: 400px; - margin: 20px auto; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); - text-align: center; - } - - .profile-container h2 { - color: black - } - .profile-picture { - width: 300px; - height: 300px; - border-radius: 50%; - margin-bottom: 15px; - } - - .profile-detail, .profile-interests { - margin: 10px 0; - } - - .profile-interests ul { - list-style-type: none; - padding: 0; - } + border: 1px solid #E0E0E0; + padding: 20px; + border-radius: 10px; + max-width: 400px; + margin: 20px auto; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + text-align: center; +} +.profile-container h2 { + color: black +} +.profile-picture { + width: 300px; + height: 300px; + border-radius: 50%; + margin-bottom: 15px; +} +.profile-detail, .profile-interests { + margin: 10px 0; +} +.profile-interests ul { + list-style-type: none; + padding: 0; +} \ No newline at end of file diff --git a/frontend/src/SCSS/navigation.css b/frontend/src/SCSS/navigation.css index 90d81a6..017dcbb 100644 --- a/frontend/src/SCSS/navigation.css +++ b/frontend/src/SCSS/navigation.css @@ -1,139 +1,137 @@ .profile-dropdown { + position: absolute; + right: 10px; + /* Changing left% to 'right' for better responsiveness and accessibility */ + top: auto; + /* May need to adjust based on surrounding containers */ + border: 1px solid #D3D3D3; + /* Replacing named colors with hex for precision */ + box-shadow: 0px 0px 10px #D3D3D3; + background-color: #FFFFFF; + width: auto; + /* Making the drop-down take full width on smaller screens */ + padding: 10px 10px; + /* Consolidating paddings into one line */ + max-width: 200px; + /* Giving a max-width to avoid overly-stretched dropdowns on larger screens */ + transition: all 0.3s ease-in-out; + /* Optional: Added transition for smoother display changes */ + border: 1px solid rgba(80, 102, 113, 0.75); + border-radius: 10px; +} +.hidden { + display: none; +} +.nav-icon > img { + height: 10px; +} +.logo-on-nav { + height: 54px !important; +} +.responsive-logo { + max-height: 54px; /* this ensures the image scales down if it's too wide for its container */ + width: auto; /* this maintains the aspect ratio of the image while scaling */ +} +.user-dropdown-menu > button { + background: none; + border: none; + font-size: 12px; + cursor: pointer; + display: flex; + flex-direction: column; +} +.drop-down-sign-out { + color: #E94C0A; +} +.nav-div { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + position: fixed; + top: 0px; + background-color: white; + border-bottom: black 1px solid; + width: 100%; +} +.nav-blank { + width: 55%; +} +.rest-of-nav { + display: flex; + align-items: center; + gap: 15px; + font-size: 12px; + max-height: 15px; +} +.nav-login > button { + background: none; + color: inherit; + border: none; + font-size: 12px; + cursor: pointer; +} +.nav-sign-up > button { + background: black; + color: white; + border-radius: 15px; + height: 25px; + cursor: pointer; +} +.nav-div-user-logged-in { + padding: 0px 10px 5px; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + height: 100px; + border-bottom: rgb(232, 232, 232) solid 0.5px; +} +.nav-blank-user-logged-in { + width: 900px; +} +.drop-down-profile-settings { + color: black; +} +.profile-create-user-logged-in { + display: flex; + flex-direction: row; + gap: 15px; +} +.user-profile-dropdown-button { + background: none; + border: none; + cursor: pointer; + display: flex; + gap: 2px; +} +.user-profile-dropdown-button:active, +.user-profile-dropdown-button:focus, +.user-profile-dropdown-button:hover { + /* Added hover here */ + outline: none; + box-shadow: none; + /* Optionally remove or change the box-shadow here to avoid the blue glow on hover */ + background-color: transparent; + /* Added this line to ensure no background color on hover */ +} +.profile-button-picture { + height: 50px !important; + color: lightgray; +} +@media only screen and (max-width: 600px) { + .profile-dropdown { position: absolute; - left: 87%; - top: 3%; + left: 60%; + top: 10%; border: 1px solid lightgrey; box-shadow: 0px 0px 20px lightgrey; background-color: white; - width: 6em; - /* padding-right: 25px; - padding-top: 10px; + width: 5em; + /* padding-top: 10px; padding-bottom: 10px; */ } - - .hidden { - display: none; - } - - .nav-icon > img{ - height: 10px; - } - - .logo-on-nav { - height: 54px !important; - } - - .responsive-logo { - max-height: 54px ; /* this ensures the image scales down if it's too wide for its container */ - width: auto; /* this maintains the aspect ratio of the image while scaling */ -} - - .user-dropdown-menu > button{ - background: none; - border: none; - font-size: 12px; - cursor: pointer; - display: flex; - flex-direction: column; - - } - - .drop-down-sign-out{ - color: red; - } - - .nav-div { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - position: fixed; - top: 0px; - background-color: white; - border-bottom: black 1px solid; - width:100% - } - - - .nav-blank { - width: 55% - } - - .rest-of-nav { - display: flex; - align-items: center; - gap: 15px; - font-size: 12px; - max-height: 15px - } - - .nav-login > button{ - background: none; - color: inherit; - border: none; - font-size: 12px; - cursor: pointer; - } - .nav-sign-up > button { - background: black; - color: white; - border-radius: 15px; - height: 25px; - cursor: pointer; - } - - .nav-div-user-logged-in { - padding: 0px 10px 5px; - display: flex; - flex-direction: row; - align-items: center; - justify-content: space-between; - height: 100px; - border-bottom: rgb(232, 232, 232) solid 0.5px; - } - - - .nav-blank-user-logged-in{ - width: 900px - } - - .drop-down-profile-settings{ - color: black; - } - .profile-create-user-logged-in { - display: flex; - flex-direction: row; - gap: 15px; - } - - - .user-profile-dropdown-button { - background: none; - border: none; - cursor: pointer; - display: flex; - gap: 2px - } - - .profile-button-picture { - height: 50px !important; - color: lightgray - } - - - @media only screen and (max-width: 600px) { - .profile-dropdown { - position: absolute; - left: 60%; - top: 10%; - border: 1px solid lightgrey; - box-shadow: 0px 0px 20px lightgrey; - background-color: white; - width: 5em; - /* padding-top: 10px; - padding-bottom: 10px; */ - } - .drop-down-sign-out { + .drop-down-sign-out { margin-top: 10px; - } } +} \ No newline at end of file diff --git a/frontend/src/SCSS/scheduling.css b/frontend/src/SCSS/scheduling.css index f872236..1b766d1 100644 --- a/frontend/src/SCSS/scheduling.css +++ b/frontend/src/SCSS/scheduling.css @@ -6,34 +6,38 @@ flex-direction: column; align-items: center; } - .scheduling-header { - font-size: 35px; - margin-bottom: 50px; + color: #007CAA; + font-size: x-large; + font-style: normal; + font-weight: 400; + line-height: normal; + margin-bottom: 3%; } - .time-dropdown-guests-slider { display: flex; - gap: 30px; + gap: 2em; align-items: center; - padding: 20px; - background-color: #f6f6f6; - border-radius: 8px; - box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1); -} - -.time-dropdown, .guests-slider { + padding: 1em; + /* background-color: #F6F6F6; */ + /* border-radius: 8px; */ + /* box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1); */ + margin-bottom: 3%; + justify-content: space-between; + width: 60%; +} +.time-dropdown, +.guests-slider { display: flex; flex-direction: column; gap: 10px; } - -.time-dropdown strong, .guests-slider strong { +.time-dropdown strong, +.guests-slider strong { font-size: 20px; - margin-bottom: 10px; + /* margin-bottom: 10px; */ color: #333; } - select { font-size: 18px; padding: 10px 15px; @@ -46,22 +50,19 @@ select { background-position: right 15px center; cursor: pointer; } - -input[type="range"] { +input[type='range'] { width: 100%; cursor: pointer; } - -select, input[type="range"] { +select, +input[type='range'] { margin-left: 10px; } - .slider { display: flex; align-items: center; gap: 20px; } - .button-div { width: 100%; display: flex; @@ -69,15 +70,35 @@ select, input[type="range"] { gap: 50px; flex-wrap: wrap; } - .button-div > button { - width: 250px; - height: 150px; - margin: 50px; - box-sizing: border-box; + display: block; + /* Added for centering button */ + width: 100%; + height: 10em; + /* Make the height scalable for different screens */ + margin: 0 auto; + /* Center the button */ + padding: 0.5em 1em; + /* Make the button more clickable */ + border: 1px solid rgba(80, 102, 113, 0.75); + border-radius: 10px; + background: #fff; + color: #007CAA; + text-align: center; + font-size: 1rem; + /* Make the font size scalable */ + transition: all 0.3s ease; + /* Added for smooth hover and focus transitions */ +} +.button-div > button:hover, +.button-div > button:focus { + background: #007CAA; + /* Change background colour when hovered or focused */ + color: #fff; + /* Change text color when hovered or focused */ + border: 1px solid #007CAA; + /* Change border color when hovered or focused */ } - - @media (max-width: 768px) { .scheduling-container { width: 100%; /* Adjusted for better mobile presentation */ @@ -86,17 +107,14 @@ select, input[type="range"] { .scheduling-header { text-align: center; } - .time-dropdown-guests-slider { flex-direction: column; gap: 20px; } - .button-div { flex-direction: column; align-items: center; } - .button-div > button { width: 100%; height: auto; @@ -104,53 +122,63 @@ select, input[type="range"] { margin: 10px 0; } } - .actions-container { display: flex; justify-content: space-around; /* Adjusted for better spacing */ width: 100%; margin-top: 20px; } - -.quick-actions, .advanced-actions { +.quick-actions, +.advanced-actions { display: flex; flex-direction: column; align-items: center; width: 45%; /* Adjusted to fit better side by side */ } - -.quick-actions p, .advanced-actions p { - font-size: 30px; +.quick-actions p, +.advanced-actions p { + font-size: auto; color: #777; text-align: center; } - .view-all-container { margin-top: 30px; width: 100%; display: flex; justify-content: center; } - .view-all-button { - padding: 15px 25px; - font-size: 18px; - background-color: #4CAF50; + display: block; + /* Added for centering button */ + width: 95%; + height: 10em; + /* Make the height scalable for different screens */ + margin: 0 auto; + /* Center the button */ + padding: 0.5em 1em; + /* Make the button more clickable */ + border: 1px solid rgba(80, 102, 113, 0.75); + border-radius: 10px; + background: #fff; + color: #007CAA; + text-align: center; + font-size: 1rem; + /* Make the font size scalable */ + transition: all 0.3s ease; + /* Added for smooth hover and focus transitions */ +} +.view-all-button:hover, +.view-all-button:focus { + background: #007CAA; + /* Change background colour when hovered or focused */ color: #fff; - border: none; - border-radius: 5px; - cursor: pointer; - transition: background-color 0.3s ease; + /* Change text color when hovered or focused */ + border: 1px solid #007CAA; + /* Change border color when hovered or focused */ } - -.view-all-button:hover { - background-color: #45a049; -} - .randomize-button { height: 100px !important; width: 250px !important; font-size: 25px; margin-top: 25px; - -} +} \ No newline at end of file From ce57c482d655532fe39ae92e6c9bb25b09e76aa9 Mon Sep 17 00:00:00 2001 From: gordonkoehn Date: Sun, 29 Oct 2023 11:01:06 +0100 Subject: [PATCH 17/17] match --- backend/main.py | 6 ++++-- backend/src/__init__.py | 5 ++++- backend/src/lunchheros/match/__init__.py | 4 ++++ backend/src/lunchheros/match/_randomize.py | 14 ++++++++++++++ 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/backend/main.py b/backend/main.py index c4ba8fa..8ade5f6 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,4 +1,5 @@ - + +import lunchheros from fastapi.encoders import jsonable_encoder from src.lunchheros.db.dbFetcher import get_encoded_data @@ -28,6 +29,7 @@ def load_current_user(userId): def load_current_user(userId: str): userData = getUserWithId(userId) queryList = getAllQueryListData() - #test = get_encoded_data(1,1,userData) + + test = lunchheros.match.match(userData) return { "currentUser" : userData, "query": queryList} \ No newline at end of file diff --git a/backend/src/__init__.py b/backend/src/__init__.py index 577f3a6..fde3f74 100644 --- a/backend/src/__init__.py +++ b/backend/src/__init__.py @@ -1 +1,4 @@ -"""Lunchheros: Backend to match people for lunch based on their interests.""" \ No newline at end of file +"""Lunchheros: Backend to match people for lunch based on their interests.""" +from lunchheros import match + +__all__ = ["match"] \ No newline at end of file diff --git a/backend/src/lunchheros/match/__init__.py b/backend/src/lunchheros/match/__init__.py index 7cecbcd..7233da5 100644 --- a/backend/src/lunchheros/match/__init__.py +++ b/backend/src/lunchheros/match/__init__.py @@ -1 +1,5 @@ """Subpackage related to matching between users into groups.""" + +from lunchheros.match import matching + +__all__ = ["matching"] \ No newline at end of file diff --git a/backend/src/lunchheros/match/_randomize.py b/backend/src/lunchheros/match/_randomize.py index c1a0750..fd05658 100644 --- a/backend/src/lunchheros/match/_randomize.py +++ b/backend/src/lunchheros/match/_randomize.py @@ -1,5 +1,7 @@ import random +from lunchheros.db.dbFetcher import parse_user_id_tolist + def _randomize_groups(group_size: int, users: list[str]) -> list[list]: """Randomize the groups of users. @@ -37,4 +39,16 @@ def _randomize_groups(group_size: int, users: list[str]) -> list[list]: return groups +def match(userids): + + # convert userids to list + userids = parse_user_id_tolist(userids) + # group size + groupsize = 5 + # randomize the groups + groups = _randomize_groups(groupsize, userids) + # return the groups + return groups + +