Skip to content

Commit

Permalink
Merge pull request #1 from Bayern-Linux/Meri_mag_Leben
Browse files Browse the repository at this point in the history
Added inital structs
  • Loading branch information
Nereuxofficial authored Aug 20, 2023
2 parents 7400b6c + de13378 commit 1602db1
Show file tree
Hide file tree
Showing 12 changed files with 409 additions and 2 deletions.
13 changes: 13 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# These are supported funding model platforms

github: Nereuxofficial
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
83 changes: 83 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: CI

on:
merge_group:
push:
branches: [main, dev]
pull_request:
branches: [main, dev]

env:
CARGO_TERM_COLOR: always

jobs:
build:
strategy:
matrix:
os: [windows-2019, ubuntu-latest]
toolchain: [stable, nightly]
runs-on: ${{ matrix.os }}
steps:

- name: Checkout
uses: actions/checkout@v2

- name: Get Rust toolchain
uses: dtolnay/rust-toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.toolchain }}
override: true

- name: Use Rust Cache
if: ${{ runner.os == 'Linux' }}
uses: Swatinem/[email protected]

- name: Run cargo check --all-targets w/ -D warnings
run: cargo check --all-targets

- name: Run cargo test w/ -D warnings
if: ${{ runner.os == 'Linux' }}
run: cargo test -- --test-threads=1
- name: Run cargo doc
if: ${{ runner.os == 'Linux' }}
run: cargo doc --no-deps --document-private-items --all-features

- name: Run build --release --all-targets
run: cargo build --release --all-targets

rustfmt:
runs-on: ubuntu-20.04
steps:

- name: Checkout
uses: actions/checkout@v2

- name: Get nightly Rust toolchain with rustfmt
uses: dtolnay/rust-toolchain@v1
with:
profile: minimal
toolchain: nightly
override: true
components: rustfmt

- name: Run cargo fmt --all -- --check
run: cargo fmt --all -- --check

clippy:
runs-on: ubuntu-20.04
steps:

- name: Checkout
uses: actions/checkout@v2

- name: Get nightly Rust toolchain with clippy
uses: dtolnay/rust-toolchain@v1
with:
profile: minimal
toolchain: nightly
override: true
components: clippy

- name: Run cargo clippy --package {{project-name}} --all-targets
run: cargo clippy --package {{project-name}} --all-targets
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/target
Cargo.lock
.idea
.vscode
*.log
.env
19 changes: 19 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "food-picker"
version = "0.1.0"
authors = ["Marion Hinkel <[email protected]>"]
license = "GPLv3"
readme = "README.md"
edition = "2021"

[dependencies]
color-eyre = "0.6.2"
tracing = "0.1.37"
serde = "1.0.163"
tracing-subscriber = "0.3.17"
dotenvy = "0.15.7"
sqlx = { version = "0.6.3", features = ["postgres", "runtime-tokio-rustls"] }
tokio = { version = "1.11.0", features = ["full"] }
liquid = "0.26.3"
actix-web = "4.3.1"
google_maps = { version= "3.3.0", features= ["rustls", "tokio", "places"] }
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
# Foodpicker
Lets you pick a random food!!!
# food-picker

# Running the project
After [installing Rust](https://rustup.rs), run the following command in the project directory:
```
cargo run --release
```
24 changes: 24 additions & 0 deletions src/food_choice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#[derive(sqlx::Type, Debug, serde::Serialize, serde::Deserialize)]
#[sqlx(type_name = "affordability", rename_all = "lowercase")]
pub enum Affordability {
Low,
Medium,
High,
}
#[derive(sqlx::Type, Debug, serde::Serialize, serde::Deserialize)]
#[sqlx(type_name = "place", rename_all = "lowercase")]
pub enum Place {
Home,
Restaurant,
Takeout,
}
#[derive(
Debug, sqlx::FromRow, sqlx::Encode, sqlx::Decode, serde::Serialize, serde::Deserialize,
)]
pub struct FoodChoice {
pub(crate) name: String,
// Cheap, Expensive, or Moderate
pub(crate) price: Affordability,
pub(crate) effort: Affordability,
pub(crate) tag: Place,
}
64 changes: 64 additions & 0 deletions src/frontend/index.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Food Choices</title>
</head>
<body>
<form id="food-form">
<label for="name">Name:</label>
<input type="text" id="name" name="name"><br><br>

<label for="price">Price:</label>
<select id="price" name="price">
<option value="Low">Low</option>
<option value="Medium">Medium</option>
<option value="High">High</option>
</select><br><br>

<label for="effort">Effort:</label>
<select id="effort" name="effort">
<option value="Low">Low</option>
<option value="Medium">Medium</option>
<option value="High">High</option>
</select><br><br>

<label for="tag">Tag:</label>
<select id="tag" name="tag">
<option value="Home">Home</option>
<option value="Restaurant">Restaurant</option>
<option value="Takeout">Takeout</option>
</select><br><br>

<button type="button" id="submit-button">Submit</button>
</form>

<script>
document.getElementById("submit-button").addEventListener("click", async () => {
const formData = new FormData(document.getElementById("food-form"));
const data = {
name: formData.get("name"),
price: formData.get("price"),
effort: formData.get("effort"),
tag: formData.get("tag"),
};
try {
const response = await fetch("/send-food-choice", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
if (response.ok) {
console.log("Data sent successfully");
} else {
console.error("Failed to send data");
}
} catch (error) {
console.error("An error occurred", error);
}
});
</script>
</body>
</html>
43 changes: 43 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use crate::food_choice::{Affordability, Place};
use actix_web::web::Data;
use actix_web::{App, HttpServer};
use sqlx::{Pool, Postgres};
use std::sync::Arc;
use tokio::sync::Mutex;

mod food_choice;
mod maps;
mod queries;
mod webpage;

struct AppState {
pool: Mutex<Pool<Postgres>>,
}

#[tokio::main]
async fn main() -> color_eyre::Result<()> {
tracing_subscriber::fmt::init();
color_eyre::install()?;
dotenvy::dotenv().ok();
let pool = sqlx::postgres::PgPool::connect(&std::env::var("DATABASE_URL")?).await?;
HttpServer::new(move || {
let app_state = Data::new(AppState {
pool: Mutex::new(pool.clone()),
});
App::new()
.app_data(app_state)
.service(webpage::index)
.service(webpage::send_food_choice)
.service(webpage::get_food_choice)
})
.bind("0.0.0.0:7373")?
.run()
.await?;
let food_choice = food_choice::FoodChoice {
name: "Pizza".to_string(),
price: Affordability::Low,
tag: Place::Home,
effort: Affordability::Low,
};
Ok(())
}
27 changes: 27 additions & 0 deletions src/maps.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use google_maps::directions::Location;
use google_maps::distance_matrix::TravelMode;
use google_maps::prelude::Decimal;
use google_maps::prelude::Place as MapsPlace;
use tracing::info;

pub async fn find_food_nearby() -> Result<Vec<MapsPlace>, google_maps::error::Error> {
let maps_client = google_maps::GoogleMapsClient::new(
std::env::var("MAPS_API_KEY")
.expect("MAPS_API_KEY not set")
.as_str(),
);
let restaurants = maps_client
.text_search("restaurants".to_string(), 5000)
.execute()
.await
.unwrap();
let filtered_restaurants = restaurants
.results
.into_iter()
.filter(|x| {
x.rating
.is_some_and(|x| x > Decimal::from_f32_retain(3.5).unwrap())
})
.collect();
Ok(filtered_restaurants)
}
7 changes: 7 additions & 0 deletions src/postgres.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CREATE TABLE food_choice (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
price TEXT NOT NULL,
effort TEXT NOT NULL,
tag TEXT NOT NULL
);
62 changes: 62 additions & 0 deletions src/queries.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use crate::food_choice::{Affordability, FoodChoice, Place};
use sqlx::{Pool, Postgres};

// Write food choice to postgres.sql via sqlx
pub async fn write_food_choice_to_db(
pool: &Pool<Postgres>,
food_choice: FoodChoice,
) -> Result<(), sqlx::Error> {
// TODO: Check if food_choice already exists in postgres.sql if so, update it
sqlx::query!(
"INSERT INTO food_choice (name, price, effort, tag) VALUES ($1, $2, $3, $4)",
food_choice.name,
food_choice.price as Affordability,
food_choice.effort as Affordability,
food_choice.tag as Place,
)
.execute(pool)
.await?;
Ok(())
}
// Delete food choice from postgres.sql via sqlx
pub async fn delete_food_choice_from_db(
pool: &Pool<Postgres>,
food_choice: FoodChoice,
food_tag: Place,
) -> Result<(), sqlx::Error> {
sqlx::query!(
"DELETE FROM food_choice WHERE name = $1 AND tag = $2",
food_choice.name,
food_tag as Place,
)
.execute(pool)
.await?;
Ok(())
}

// Read food choice from postgres.sql via sqlx
pub async fn read_food_choice_from_db(
pool: &Pool<Postgres>,
name: String,
) -> Result<FoodChoice, sqlx::Error> {
let food_choice = sqlx::query_as!(
FoodChoice,
r#"SELECT name, price as "price: _", effort as "effort: _", tag as "tag: _" FROM food_choice WHERE name = $1"#,
name
)
.fetch_one(pool)
.await?;
Ok(food_choice)
}
// Read random food choice from postgres.sql via sqlx
pub async fn read_random_food_choice_from_db(
pool: &Pool<Postgres>,
) -> Result<FoodChoice, sqlx::Error> {
let food_choice = sqlx::query_as!(
FoodChoice,
r#"SELECT name, price as "price: _", effort as "effort: _", tag as "tag: _" FROM food_choice ORDER BY RANDOM() LIMIT 1"#
)
.fetch_one(pool)
.await?;
Ok(food_choice)
}
Loading

0 comments on commit 1602db1

Please sign in to comment.