From ecda05833e8d8099715fdcdeaf5964edd2b3bc7e Mon Sep 17 00:00:00 2001 From: st170001 Date: Wed, 24 Jan 2024 16:05:13 +0100 Subject: [PATCH] Adapt for user specific queries disallowing general wishlist access --- src/foreign_types.rs | 8 ------ src/main.rs | 6 +++-- src/mutation.rs | 3 ++- src/query.rs | 50 ++++++------------------------------ src/user.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++ src/wishlist.rs | 11 +++++--- 6 files changed, 81 insertions(+), 57 deletions(-) create mode 100644 src/user.rs diff --git a/src/foreign_types.rs b/src/foreign_types.rs index 049c754..ac728a0 100644 --- a/src/foreign_types.rs +++ b/src/foreign_types.rs @@ -3,14 +3,6 @@ use bson::{doc, Bson, Uuid}; use serde::{Deserialize, Serialize}; use std::{cmp::Ordering, hash::Hash}; -/// Foreign type of a user. -#[derive(Debug, Serialize, Deserialize, Hash, Eq, PartialEq, Clone, SimpleObject)] -#[graphql(unresolvable)] -pub struct User { - /// UUID of the user. - pub _id: Uuid, -} - /// Foreign type of a product variant. #[derive(Debug, Serialize, Deserialize, Hash, Eq, PartialEq, Copy, Clone, SimpleObject)] #[graphql(unresolvable)] diff --git a/src/main.rs b/src/main.rs index 8dd57a0..f4d9778 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,6 @@ use axum::{ use clap::{arg, command, Parser}; use simple_logger::SimpleLogger; -use foreign_types::User; use log::info; use mongodb::{bson::DateTime, options::ClientOptions, Client, Collection, Database}; @@ -33,7 +32,10 @@ use mutation::Mutation; mod app_callback_service; use app_callback_service::AppCallbackService; -use crate::foreign_types::ProductVariant; +use foreign_types::ProductVariant; + +mod user; +use user::User; mod base_connection; mod foreign_types; diff --git a/src/mutation.rs b/src/mutation.rs index 92ef6f6..852fab4 100644 --- a/src/mutation.rs +++ b/src/mutation.rs @@ -9,8 +9,9 @@ use mongodb::{ Collection, Database, }; +use crate::user::User; use crate::{ - foreign_types::{ProductVariant, User}, + foreign_types::ProductVariant, mutation_input_structs::{AddWishlistInput, UpdateWishlistInput}, query::query_wishlist, wishlist::Wishlist, diff --git a/src/query.rs b/src/query.rs index db51b9b..ec04907 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,54 +1,20 @@ -use crate::{ - base_connection::{BaseConnection, FindResultWrapper}, - order_datatypes::WishlistOrderInput, - wishlist_connection::WishlistConnection, - Wishlist, -}; +use crate::{user::User, Wishlist}; use async_graphql::{Context, Error, Object, Result}; -use bson::Document; + use bson::Uuid; -use mongodb::{bson::doc, options::FindOptions, Collection, Database}; -use mongodb_cursor_pagination::{error::CursorError, FindResult, PaginatedCursor}; +use mongodb::{bson::doc, Collection, Database}; /// Describes GraphQL wishlist queries. pub struct Query; #[Object] impl Query { - /// Retrieves all wishlists. - async fn wishlists<'a>( + /// Retrieve user with wishlists. + async fn user<'a>( &self, - ctx: &Context<'a>, - #[graphql(desc = "Describes that the `first` N wishlists should be retrieved.")] - first: Option, - #[graphql(desc = "Describes how many wishlists should be skipped at the beginning.")] - skip: Option, - #[graphql(desc = "Specifies the order in which wishlists are retrieved.")] order_by: Option< - WishlistOrderInput, - >, - ) -> Result { - let db_client = ctx.data_unchecked::(); - let collection: Collection = db_client.collection::("wishlists"); - let wishlist_order = order_by.unwrap_or_default(); - let sorting_doc = doc! {wishlist_order.field.unwrap_or_default().as_str(): i32::from(wishlist_order.direction.unwrap_or_default())}; - let find_options = FindOptions::builder() - .skip(skip) - .limit(first.map(|v| i64::from(v))) - .sort(sorting_doc) - .build(); - let document_collection = collection.clone_with_type::(); - let maybe_find_results: Result, CursorError> = - PaginatedCursor::new(Some(find_options.clone()), None, None) - .find(&document_collection, None) - .await; - match maybe_find_results { - Ok(find_results) => { - let find_result_wrapper = FindResultWrapper(find_results); - let connection = Into::>::into(find_result_wrapper); - Ok(Into::::into(connection)) - } - Err(_) => return Err(Error::new("Retrieving wishlists failed in MongoDB.")), - } + #[graphql(desc = "UUID of user to retrieve.")] id: Uuid, + ) -> Result { + Ok(User { _id: id }) } /// Retrieves wishlist of specific id. diff --git a/src/user.rs b/src/user.rs new file mode 100644 index 0000000..2328930 --- /dev/null +++ b/src/user.rs @@ -0,0 +1,60 @@ +use async_graphql::{ComplexObject, Context, Error, Result, SimpleObject}; +use bson::{doc, Document, Uuid}; +use mongodb::{options::FindOptions, Collection, Database}; +use mongodb_cursor_pagination::{error::CursorError, FindResult, PaginatedCursor}; +use serde::{Deserialize, Serialize}; + +use crate::{ + base_connection::{BaseConnection, FindResultWrapper}, + order_datatypes::CommonOrderInput, + wishlist::Wishlist, + wishlist_connection::WishlistConnection, +}; + +/// Type of a user owning wishlists. +#[derive(Debug, Serialize, Deserialize, Hash, Eq, PartialEq, Clone, SimpleObject)] +#[graphql(complex)] +pub struct User { + /// UUID of the user. + pub _id: Uuid, +} + +#[ComplexObject] +impl User { + /// Retrieves wishlists of user. + async fn wishlists<'a>( + &self, + ctx: &Context<'a>, + #[graphql(desc = "Describes that the `first` N wishlists should be retrieved.")] + first: Option, + #[graphql(desc = "Describes how many wishlists should be skipped at the beginning.")] + skip: Option, + #[graphql(desc = "Specifies the order in which wishlists are retrieved.")] order_by: Option< + CommonOrderInput, + >, + ) -> Result { + let db_client = ctx.data_unchecked::(); + let collection: Collection = db_client.collection::("wishlists"); + let wishlist_order = order_by.unwrap_or_default(); + let sorting_doc = doc! {wishlist_order.field.unwrap_or_default().as_str(): i32::from(wishlist_order.direction.unwrap_or_default())}; + let find_options = FindOptions::builder() + .skip(skip) + .limit(first.map(|v| i64::from(v))) + .sort(sorting_doc) + .build(); + let document_collection = collection.clone_with_type::(); + let filter = doc! {"user._id": self._id}; + let maybe_find_results: Result, CursorError> = + PaginatedCursor::new(Some(find_options.clone()), None, None) + .find(&document_collection, Some(&filter)) + .await; + match maybe_find_results { + Ok(find_results) => { + let find_result_wrapper = FindResultWrapper(find_results); + let connection = Into::>::into(find_result_wrapper); + Ok(Into::::into(connection)) + } + Err(_) => return Err(Error::new("Retrieving wishlists failed in MongoDB.")), + } + } +} diff --git a/src/wishlist.rs b/src/wishlist.rs index c2cd6a4..1a47194 100644 --- a/src/wishlist.rs +++ b/src/wishlist.rs @@ -9,9 +9,10 @@ use bson::Uuid; use serde::{Deserialize, Serialize}; use crate::{ - foreign_types::{ProductVariant, User}, + foreign_types::ProductVariant, order_datatypes::{CommonOrderInput, OrderDirection}, product_variant_connection::ProductVariantConnection, + user::User, }; /// The Wishlist of a user. @@ -37,11 +38,13 @@ impl Wishlist { /// Retrieves product variants. async fn product_variants( &self, - #[graphql(desc = "Describes that the `first` N wishlists should be retrieved.")] + #[graphql(desc = "Describes that the `first` N product variants should be retrieved.")] first: Option, - #[graphql(desc = "Describes how many wishlists should be skipped at the beginning.")] + #[graphql( + desc = "Describes how many product variants should be skipped at the beginning." + )] skip: Option, - #[graphql(desc = "Specifies the order in which wishlists are retrieved.")] order_by: Option< + #[graphql(desc = "Specifies the order in which product variants are retrieved.")] order_by: Option< CommonOrderInput, >, ) -> Result {