diff --git a/crates/common/src/http/extractors/optuser.rs b/crates/common/src/http/extractors/optuser.rs index 627ca06..8aaf8ba 100644 --- a/crates/common/src/http/extractors/optuser.rs +++ b/crates/common/src/http/extractors/optuser.rs @@ -32,6 +32,7 @@ where { type Rejection = String; + #[allow(clippy::bind_instead_of_map)] async fn from_request_parts(parts: &mut Parts, _: &S) -> Result { parts .headers diff --git a/crates/common/src/model/auth/user.rs b/crates/common/src/model/auth/user.rs index 52524b4..b397749 100644 --- a/crates/common/src/model/auth/user.rs +++ b/crates/common/src/model/auth/user.rs @@ -21,7 +21,7 @@ use uuid::Uuid; #[derive(Clone, Debug, Eq, PartialEq)] pub struct User { - uuid: Uuid, + pub uuid: Uuid, email: String, password: Option, lastname: Option, diff --git a/crates/media/src/api/router.rs b/crates/media/src/api/router.rs index 885502f..e0c4582 100644 --- a/crates/media/src/api/router.rs +++ b/crates/media/src/api/router.rs @@ -15,9 +15,13 @@ * along with this program. If not, see . */ +use std::sync::Arc; + use axum::routing::{delete, get, patch, post}; use axum::Router; +use crate::repository::repository::{MediaRepository, MediaRepositoryState}; + use super::routes::delete_media_id::delete_media_id; use super::routes::get_albums::get_albums; use super::routes::get_albums_id::get_albums_id; @@ -38,6 +42,11 @@ impl MediaApi { where S: Send + Sync + 'static + Clone, { + let media_repository: MediaRepositoryState = Arc::new(MediaRepository { + db_url: "", + db: sea_orm::DatabaseConnection::Disconnected, + }); + Router::new() // Returns a list of owned media items for current user // 200 Ok @@ -56,8 +65,7 @@ impl MediaApi { // 200 - Ok // 400 Bad Request - The request body was malformed or a field violated its constraints. // 401 Unauthorized - You are unauthenticated - // 403 Forbidden - You are authenticated but have no permission to manage the target user. - // 500 Internal Server Error + // 403 Forbidden - You are authenticated but have no permission to manage the target user. // 500 Internal Server Error .route("/media/:media_id", get(get_media_id)) // Add files for a specific media item .route("/media/:media_id", post(post_media_id)) @@ -78,6 +86,7 @@ impl MediaApi { // unshares the given album .route("/albums/:entity_id/unshare", patch(patch_albums_id_unshare)) .layer(tower_http::trace::TraceLayer::new_for_http()) + .with_state(media_repository) } } diff --git a/crates/media/src/api/routes/get_media.rs b/crates/media/src/api/routes/get_media.rs index aa9e35c..88e7cb3 100644 --- a/crates/media/src/api/routes/get_media.rs +++ b/crates/media/src/api/routes/get_media.rs @@ -1,10 +1,13 @@ //! Returns a list of owned media items for current user //! +use axum::extract::State; use axum::{extract::Query, http::StatusCode, Json}; -use common::http::extractors::{self, optuser::OptionalUser}; use common::model::auth::user::User; use serde::{Deserialize, Serialize}; use std::result::Result; +use tracing::error; + +use crate::repository::repository::MediaRepositoryState; #[derive(Serialize, Deserialize)] pub(crate) struct MediaListQuery { @@ -13,9 +16,19 @@ pub(crate) struct MediaListQuery { } pub(crate) async fn get_media( - user: OptionalUser, + State(repo): State, + user: User, Query(query): Query, ) -> Result, StatusCode> { + let items = repo.get_media_items_for_user(user.uuid).await; + match items { + Ok(i) => { + error!("Found {} items for user.", i.len()); + } + Err(_) => { + error!("Failed to get media items!"); + } + } //tracing::error!("GET /media user={}", user); // TODO: check auth header // TODO: read list from persistency @@ -23,8 +36,8 @@ pub(crate) async fn get_media( Ok(Json( format!( "list media items. limit={}, offset={}", - query.limit.unwrap_or_else(|| 1000), - query.offset.unwrap_or_else(|| 0) + query.limit.unwrap_or(1000), + query.offset.unwrap_or(0) ) .to_owned(), )) @@ -58,6 +71,6 @@ mod tests { .unwrap(); // then - assert_eq!(response.status(), StatusCode::OK); + assert_eq!(response.status(), StatusCode::UNAUTHORIZED); } } diff --git a/crates/media/src/data/media_item.rs b/crates/media/src/data/media_item.rs index 36e24d6..44df9d5 100644 --- a/crates/media/src/data/media_item.rs +++ b/crates/media/src/data/media_item.rs @@ -37,7 +37,7 @@ impl MediaItem { fn new(name: &'static str) -> Self { MediaItem { uuid: "", - name: name, + name, date_added: Instant::now(), date_taken: None, location: None, diff --git a/crates/media/src/repository/mod.rs b/crates/media/src/repository/mod.rs index f08d9a4..8a7da4a 100644 --- a/crates/media/src/repository/mod.rs +++ b/crates/media/src/repository/mod.rs @@ -15,66 +15,4 @@ * along with this program. If not, see . */ -use std::sync::Arc; - -use axum::async_trait; -use mockall::predicate::*; -use sea_orm::DatabaseConnection; - -use crate::data::error::DataAccessError; -use crate::data::media_item::MediaItem; -use crate::data::open_db_conn; - -pub struct MediaRepository { - #[allow(dead_code)] - db_url: &'static str, - #[allow(dead_code)] - db: DatabaseConnection, -} - -#[allow(dead_code)] -pub(crate) type MediaRepositoryState = Arc; - -/// MockPhotosRepositoryTrait is created by automock macro -#[cfg_attr(test, mockall::automock)] -#[async_trait] -trait MediaRepositoryTrait { - #[allow(dead_code)] - async fn new(db_url: &'static str) -> Self; - - // Gets a list of media items from the DB filted by user_id - async fn get_media_items_for_user( - &self, - user_id: &str, - ) -> Result, DataAccessError>; -} - -impl MediaRepository { - #[allow(dead_code)] - pub(crate) async fn new() -> Self { - Self { - db_url: "", - db: DatabaseConnection::Disconnected, - } - } -} - -#[async_trait] -impl MediaRepositoryTrait for MediaRepository { - async fn new(db_url: &'static str) -> MediaRepository { - let db = open_db_conn("sqlite://data/media.sqlita".to_string()) - .await - .expect("Could not connect do database 'media'!"); - - MediaRepository { db, db_url } - } - - async fn get_media_items_for_user( - &self, - _user_id: &str, - ) -> Result, DataAccessError> { - // TODO: read from database - - Err(DataAccessError::OtherError) - } -} +pub mod repository; diff --git a/crates/media/src/repository/repository.rs b/crates/media/src/repository/repository.rs new file mode 100644 index 0000000..5e8698d --- /dev/null +++ b/crates/media/src/repository/repository.rs @@ -0,0 +1,90 @@ +/* Photos.network ยท A privacy first photo storage and sharing service for fediverse. + * Copyright (C) 2020 Photos network developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +use std::sync::Arc; + +use axum::async_trait; +use mockall::predicate::*; +use sea_orm::DatabaseConnection; +use tracing::info; +use uuid::Uuid; + +use crate::data::error::DataAccessError; +use crate::data::media_item::MediaItem; +use crate::data::open_db_conn; + +pub struct MediaRepository { + #[allow(dead_code)] + pub(crate) db_url: &'static str, + #[allow(dead_code)] + pub(crate) db: DatabaseConnection, +} + +#[allow(dead_code)] +pub(crate) type MediaRepositoryState = Arc; + +/// MockPhotosRepositoryTrait is created by automock macro +#[cfg_attr(test, mockall::automock)] +#[async_trait] +trait MediaRepositoryTrait { + #[allow(dead_code)] + async fn new(db_url: &'static str) -> Self; + + // Gets a list of media items from the DB filted by user_id + async fn get_media_items_for_user( + &self, + user_id: Uuid, + ) -> Result, DataAccessError>; +} + +impl MediaRepository { + #[allow(dead_code)] + pub(crate) async fn new() -> Self { + Self { + db_url: "sqlite://data/media.sqlite", + db: DatabaseConnection::Disconnected, + } + } + pub(crate) async fn get_media_items_for_user( + &self, + user_id: Uuid, + ) -> Result, DataAccessError> { + info!("get items for user {}", user_id); + + Ok(vec![]) + } +} + +#[async_trait] +impl MediaRepositoryTrait for MediaRepository { + async fn new(db_url: &'static str) -> MediaRepository { + let db = open_db_conn(db_url.to_string()) + .await + .expect("Could not connect do database 'media'!"); + + MediaRepository { db, db_url } + } + + async fn get_media_items_for_user( + &self, + _user_id: Uuid, + ) -> Result, DataAccessError> { + // TODO: read from database + + Err(DataAccessError::OtherError) + } +} diff --git a/crates/oauth_authentication/src/lib.rs b/crates/oauth_authentication/src/lib.rs index ad36e33..9e58400 100644 --- a/crates/oauth_authentication/src/lib.rs +++ b/crates/oauth_authentication/src/lib.rs @@ -38,6 +38,7 @@ use thiserror::Error; use openidconnect::{OAuth2TokenResponse, TokenResponse}; pub struct AuthenticationManager { + #[allow(clippy::type_complexity)] pub client: openidconnect::Client< openidconnect::EmptyAdditionalClaims, openidconnect::core::CoreAuthDisplay, @@ -68,6 +69,7 @@ pub struct AuthenticationManager { openidconnect::core::CoreRevocableToken, openidconnect::StandardErrorResponse, >, + #[allow(clippy::type_complexity)] pub provider_metadata: ProviderMetadata< EmptyAdditionalProviderMetadata, openidconnect::core::CoreAuthDisplay, @@ -105,7 +107,7 @@ impl AuthenticationManager { pub fn new() -> Result { tracing::error!("run setup"); - let foo = CoreProviderMetadata::discover( + let provider_metadata = CoreProviderMetadata::discover( &IssuerUrl::new("https://accounts.google.com".to_string())?, http_client, )?; @@ -115,9 +117,9 @@ impl AuthenticationManager { PkceCodeChallenge::new_random_sha256(); Ok(Self { - provider_metadata: foo.clone(), + provider_metadata: provider_metadata.clone(), client: CoreClient::from_provider_metadata( - foo, + provider_metadata, ClientId::new( "953760225864-77il4losuech1dtsea36tmma2e8bko3h.apps.googleusercontent.com" .to_string(), @@ -133,6 +135,7 @@ impl AuthenticationManager { }) } + #[allow(clippy::type_complexity)] pub fn create_authorization_url( client: openidconnect::Client< openidconnect::EmptyAdditionalClaims, @@ -188,6 +191,7 @@ impl AuthenticationManager { Ok(nonce) } + #[allow(clippy::type_complexity)] pub fn exchange_code( client: openidconnect::Client< openidconnect::EmptyAdditionalClaims, diff --git a/documentation/http/get_media.hurl b/documentation/http/get_media.hurl new file mode 100644 index 0000000..5abaa98 --- /dev/null +++ b/documentation/http/get_media.hurl @@ -0,0 +1,5 @@ +GET http://127.0.0.1:7777/media +Authorization: FakeToken + +HTTP 200 +