diff --git a/migrations/2020-08-08-015035_favorites/down.sql b/migrations/2020-08-08-015035_favorites/down.sql new file mode 100644 index 0000000..19e00d6 --- /dev/null +++ b/migrations/2020-08-08-015035_favorites/down.sql @@ -0,0 +1 @@ +DROP TABLE favorites diff --git a/migrations/2020-08-08-015035_favorites/up.sql b/migrations/2020-08-08-015035_favorites/up.sql new file mode 100644 index 0000000..6ea8a23 --- /dev/null +++ b/migrations/2020-08-08-015035_favorites/up.sql @@ -0,0 +1,5 @@ +CREATE TABLE favorites ( + id INTEGER PRIMARY KEY NOT NULL, + userid INTEGER NOT NULL, + path TEXT NOT NULL +) diff --git a/src/data/mod.rs b/src/data/mod.rs index 288d3c2..e95068e 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -79,3 +79,8 @@ pub struct CreateAccountRequest { pub password: String, pub confirmation: String, } + +#[derive(Deserialize)] +pub struct AddFavoriteRequest { + pub path: String, +} diff --git a/src/database/mod.rs b/src/database/mod.rs index 66afe58..22a9dc1 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -3,7 +3,7 @@ use diesel::prelude::*; use diesel::sqlite::SqliteConnection; use dotenv::dotenv; -use crate::database::models::{InsertUser, User}; +use crate::database::models::{Favorite, InsertFavorite, InsertUser, User}; mod models; mod schema; @@ -68,3 +68,25 @@ pub fn user_exists(name: &str) -> bool { .first() .is_some() } + +pub fn add_favorite(user_id: i32, favorite_path: String) { + use schema::favorites::dsl::*; + + let connection = connect(); + diesel::insert_into(favorites) + .values(InsertFavorite { + userid: &user_id, + path: &favorite_path, + }) + .execute(&connection) + .unwrap(); +} + +pub fn get_favorites(user_id: i32) -> Vec { + use schema::favorites::dsl::*; + + favorites + .filter(userid.eq(user_id)) + .load::(&connect()) + .unwrap_or_default() +} diff --git a/src/database/models.rs b/src/database/models.rs index 5e22d11..dca23ba 100644 --- a/src/database/models.rs +++ b/src/database/models.rs @@ -1,4 +1,4 @@ -use crate::database::schema::users; +use crate::database::schema::{favorites, users}; use serde::Serialize; #[derive(Insertable)] @@ -15,3 +15,17 @@ pub struct User { #[serde(skip_serializing)] pub password: String, } + +#[derive(Insertable)] +#[table_name = "favorites"] +pub struct InsertFavorite<'a> { + pub userid: &'a i32, + pub path: &'a str, +} + +#[derive(Serialize, Queryable, Clone, Debug)] +pub struct Favorite { + pub id: i32, + pub userid: i32, + pub path: String, +} diff --git a/src/database/schema.rs b/src/database/schema.rs index b746bf7..e254eee 100644 --- a/src/database/schema.rs +++ b/src/database/schema.rs @@ -1,3 +1,11 @@ +table! { + favorites (id) { + id -> Integer, + userid -> Integer, + path -> Text, + } +} + table! { users (id) { id -> Integer, @@ -5,3 +13,5 @@ table! { password -> Text, } } + +allow_tables_to_appear_in_same_query!(favorites, users,); diff --git a/src/main.rs b/src/main.rs index 698cbed..b89c240 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,14 +6,14 @@ use actix_files::NamedFile; use actix_web::web::{HttpRequest, HttpResponse, Json}; use actix_web::{get, post, web, App, HttpServer, Responder}; use chrono::{Duration, Utc}; -use data::{LoginRequest, ThumbnailRequest}; +use data::{AddFavoriteRequest, LoginRequest, ThumbnailRequest}; use jsonwebtoken::{encode, EncodingKey, Header}; use rayon::prelude::*; use serde::Serialize; use std::path::{Path, PathBuf}; use crate::data::{secret_key, Claims, CreateAccountRequest, Token}; -use crate::database::{create_user, get_user, user_exists}; +use crate::database::{add_favorite, create_user, get_favorites, get_user, user_exists}; use crate::files::{is_valid_path, list_files}; use crate::video::*; @@ -170,6 +170,28 @@ async fn get_video_part( } } +#[get("image/favorites")] +async fn favorites(claims: Claims) -> impl Responder { + let favorites = get_favorites(claims.sub.parse::().unwrap()) + .into_iter() + .map(|favorite| favorite.path) + .collect::>(); + HttpResponse::Ok().json(PhotosResponse { + photos: &favorites, + dirs: &Vec::new(), + }) +} + +#[post("image/favorites")] +async fn post_add_favorite(claims: Claims, body: web::Json) -> impl Responder { + if let Ok(user_id) = claims.sub.parse::() { + add_favorite(user_id, body.path.clone()); + HttpResponse::Ok() + } else { + HttpResponse::BadRequest() + } +} + async fn create_thumbnails() { let thumbs = &dotenv::var("THUMBNAILS").expect("THUMBNAILS not defined"); let thumbnail_directory: &Path = Path::new(thumbs); @@ -206,7 +228,7 @@ async fn create_thumbnails() { let path = entry.path(); let relative_path = &path.strip_prefix(&images).unwrap(); let thumb_path = Path::new(thumbnail_directory).join(relative_path); - return !thumb_path.exists(); + !thumb_path.exists() }) .map(|entry| (image::open(entry.path()), entry.path().to_path_buf())) .filter(|(img, _)| img.is_ok()) @@ -238,6 +260,8 @@ async fn main() -> std::io::Result<()> { .service(generate_video) .service(stream_video) .service(get_video_part) + .service(favorites) + .service(post_add_favorite) }) .bind(dotenv::var("BIND_URL").unwrap())? .bind("localhost:8088")?