Add user input database verification

This commit is contained in:
2024-03-25 11:31:42 +01:00
parent d0a8306a20
commit 206e340012
3 changed files with 160 additions and 22 deletions

View File

@@ -1,4 +1,7 @@
use std::i64;
use anyhow::Result; use anyhow::Result;
use ratatui::widgets::block::title;
use sqlx::{Row, SqlitePool}; use sqlx::{Row, SqlitePool};
pub struct Database { pub struct Database {
@@ -7,11 +10,49 @@ pub struct Database {
impl Database { impl Database {
pub async fn new() -> Result<Self> { pub async fn new() -> Result<Self> {
let pool = SqlitePool::connect("sqlite:ratings.db").await?; let pool = SqlitePool::connect("sqlite://ratings.db?mode=rwc").await?;
Ok(Database { pool }) Ok(Database { pool })
} }
pub async fn add_user(&self, name: &str, number: i64) -> Result<i64> { pub async fn create_tables(&self) -> Result<()> {
let mut conn = self.pool.acquire().await?;
let _ = sqlx::query(
r#"
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS interprets (
id INTEGER PRIMARY KEY,
interpret TEXT NOT NULL,
UNIQUE(interpret)
);
CREATE TABLE IF NOT EXISTS songs (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
interpret_id INTEGER NOT NULL,
FOREIGN KEY("interpret_id") REFERENCES interpret (id),
UNIQUE(title, interpret_id)
);
CREATE TABLE IF NOT EXISTS ratings (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL,
song_id INTEGER NOT NULL,
rating INTEGER NOT NULL,
FOREIGN KEY("user_id") REFERENCES users (id),
FOREIGN KEY("song_id") REFERENCES songs (id),
UNIQUE(user_id, song_id)
);
"#,
)
.execute(&mut *conn)
.await?;
Ok(())
}
pub async fn add_user(&self, user_id: i64, name: &str) -> Result<i64> {
let mut conn = self.pool.acquire().await?; let mut conn = self.pool.acquire().await?;
let id = sqlx::query( let id = sqlx::query(
@@ -20,8 +61,8 @@ impl Database {
VALUES (?1, ?2) VALUES (?1, ?2)
"#, "#,
) )
.bind(user_id)
.bind(name) .bind(name)
.bind(number)
.execute(&mut *conn) .execute(&mut *conn)
.await? .await?
.last_insert_rowid(); .last_insert_rowid();
@@ -29,7 +70,7 @@ impl Database {
Ok(id) Ok(id)
} }
pub async fn user_exists(&self, number: i64) -> Result<i64> { pub async fn user_exists(&self, user_id: i64) -> Result<i64> {
let mut conn = self.pool.acquire().await?; let mut conn = self.pool.acquire().await?;
let record = sqlx::query( let record = sqlx::query(
@@ -38,7 +79,7 @@ impl Database {
WHERE id = ? WHERE id = ?
"#, "#,
) )
.bind(number) .bind(user_id)
.fetch_one(&mut *conn) .fetch_one(&mut *conn)
.await?; .await?;
@@ -46,4 +87,78 @@ impl Database {
Ok(id) Ok(id)
} }
pub async fn user_add_rating(
&self,
user_id: i64,
interpret: &str,
song: &str,
rating: i64,
) -> Result<()> {
let mut conn = self.pool.acquire().await?;
// Add interpret
let _ = sqlx::query(
r#"
INSERT OR IGNORE INTO interprets (interpret)
VALUES (?1)
"#,
)
.bind(interpret)
.execute(&mut *conn)
.await?;
// Get the interpret ID
let record = sqlx::query(
r#"
SELECT id FROM interprets
WHERE interpret = ?1
"#,
)
.bind(interpret)
.fetch_one(&mut *conn)
.await?;
let interpret_id: i64 = record.try_get("id")?;
// Add the song
let _ = sqlx::query(
r#"
INSERT OR IGNORE INTO songs (title, interpret_id)
VALUES (?1, ?2)
"#,
)
.bind(song)
.bind(interpret_id)
.execute(&mut *conn)
.await?;
// Get the song ID
let record = sqlx::query(
r#"
SELECT id FROM songs
WHERE title = ?1
"#,
)
.bind(song)
.fetch_one(&mut *conn)
.await?;
let song_id: i64 = record.try_get("id")?;
// Add the rating
let _ = sqlx::query(
r#"
INSERT INTO ratings (user_id, song_id, rating)
VALUES (?1, ?2, ?3)
"#,
)
.bind(user_id)
.bind(song_id)
.bind(rating)
.execute(&mut *conn)
.await?;
Ok(())
}
} }

View File

@@ -8,10 +8,17 @@ use tokio;
async fn main() { async fn main() {
let player = player::MprisPlayer::new().expect("Could not create player"); let player = player::MprisPlayer::new().expect("Could not create player");
let (usernumber, userrating) = userinterface::get_user_rating().expect("Lala"); let db = database::Database::new()
.await
.expect("Could not create database");
let (usernumber, userrating) = userinterface::get_user_rating(&db).await.expect("Lala");
let track = player let track = player
.get_interpret_and_track() .get_interpret_and_track()
.expect("Could not read track"); .expect("Could not read track");
println!("User: {usernumber} with rating: {userrating}: {track}"); println!("User: {usernumber} with rating: {userrating}: {track}");
db.create_tables().await.unwrap();
//db.add_user(1, "Janek").await.unwrap();
} }

View File

@@ -12,19 +12,35 @@ use tui_textarea::{Input, Key, TextArea};
use anyhow::Result; use anyhow::Result;
fn validate_user(textarea: &mut TextArea) -> bool { use crate::database::Database;
if let Err(_) = textarea.lines()[0].parse::<u64>() {
textarea.set_style(Style::default().fg(Color::LightRed)); async fn validate_user(textarea: &mut TextArea<'_>, db: &Database) -> bool {
textarea.set_block( match textarea.lines()[0].parse::<u64>() {
Block::default() Err(_) => {
.borders(Borders::ALL) textarea.set_style(Style::default().fg(Color::LightRed));
.title(format!("ERROR: Please enter a valid user number")), textarea.set_block(
); Block::default()
false .borders(Borders::ALL)
} else { .title(format!("ERROR: Please enter a valid user number")),
textarea.set_style(Style::default().fg(Color::LightGreen)); );
textarea.set_block(Block::default().borders(Borders::ALL).title("OK")); false
true }
Ok(value) => {
let db_user = db.user_exists(value as i64).await.is_ok();
if db_user {
textarea.set_style(Style::default().fg(Color::LightGreen));
textarea.set_block(Block::default().borders(Borders::ALL).title("OK"));
true
} else {
textarea.set_style(Style::default().fg(Color::LightRed));
textarea.set_block(
Block::default()
.borders(Borders::ALL)
.title(format!("ERROR: Please enter a valid user number")),
);
false
}
}
} }
} }
@@ -56,7 +72,7 @@ fn validate_rating(textarea: &mut TextArea) -> bool {
} }
} }
pub fn get_user_rating() -> Result<(String, String)> { pub async fn get_user_rating(db: &Database) -> Result<(String, String)> {
let stdout = io::stdout(); let stdout = io::stdout();
let mut stdout = stdout.lock(); let mut stdout = stdout.lock();
@@ -70,7 +86,7 @@ pub fn get_user_rating() -> Result<(String, String)> {
textarea.set_placeholder_text("USER: Enter a valid user number (e.g. 156)"); textarea.set_placeholder_text("USER: Enter a valid user number (e.g. 156)");
let layout = let layout =
Layout::default().constraints([Constraint::Length(3), Constraint::Min(1)].as_slice()); Layout::default().constraints([Constraint::Length(3), Constraint::Min(1)].as_slice());
let mut is_valid = validate_user(&mut textarea); let mut is_valid = validate_user(&mut textarea, db).await;
loop { loop {
term.draw(|f| { term.draw(|f| {
@@ -95,7 +111,7 @@ pub fn get_user_rating() -> Result<(String, String)> {
input => { input => {
// TextArea::input returns if the input modified its text // TextArea::input returns if the input modified its text
if textarea.input(input) { if textarea.input(input) {
is_valid = validate_user(&mut textarea); is_valid = validate_user(&mut textarea, db).await;
} }
} }
} }