diff --git a/bin/core/src/requests/read/search.rs b/bin/core/src/requests/read/search.rs index e9630e4f8..a9f7b202a 100644 --- a/bin/core/src/requests/read/search.rs +++ b/bin/core/src/requests/read/search.rs @@ -1,6 +1,6 @@ use std::str::FromStr; -use anyhow::Context; +use anyhow::{anyhow, Context}; use async_trait::async_trait; use monitor_types::{ entities::{ @@ -14,7 +14,7 @@ use monitor_types::{ ServerListItem, }, }; -use mungos::mongodb::bson::{doc, oid::ObjectId, Document}; +use mungos::mongodb::bson::{doc, oid::ObjectId}; use resolver_api::Resolve; use crate::{auth::RequestUser, state::State}; @@ -25,7 +25,7 @@ const ALL_RESOURCE_TYPES: [ResourceTargetVariant; 4] = [Server, Build, Deploymen impl Resolve for State { async fn resolve( &self, - FindResources { tags }: FindResources, + FindResources { search, tags }: FindResources, user: RequestUser, ) -> anyhow::Result { let SeperateTags { @@ -34,7 +34,16 @@ impl Resolve for State { custom_tag_ids, } = seperate_tags(tags); - let mut query = Document::new(); + let mut query = doc! { + "name": { "$regex": search } + }; + + if !user.is_admin { + query.insert( + format!("permissions.{}", user.id), + doc! { "$in": ["read", "execute", "update"] }, + ); + } if !custom_tag_ids.is_empty() { query.insert("tags", doc! { "$all": custom_tag_ids }); @@ -55,13 +64,10 @@ impl Resolve for State { .context("failed to parse server id as ObjectId") }) .collect::>>()?; - self.db - .servers - .get_some(doc! { "_id": { "$in": server_ids } }, None) - .await? - } - .into_iter() - .filter(|s| s.get_user_permissions(&user.id) > PermissionLevel::None); + let mut query = query.clone(); + query.insert("_id", doc! { "$in": server_ids }); + self.db.servers.get_some(query, None).await? + }; for server in servers { let status = self .server_status_cache @@ -163,7 +169,7 @@ impl Resolve for State { response.repos.push(item); } } - _ => unreachable!(), + _ => return Err(anyhow!("{resource_type} is not compatible with this route")), } } @@ -186,7 +192,7 @@ fn seperate_tags(tags: Vec) -> SeperateTags { Tag::Custom { tag_id } => seperated.custom_tag_ids.push(tag_id), Tag::Server { server_id } => seperated.server_ids.push(server_id), Tag::ResourceType { resource } => { - if !matches!(resource, Builder | System,) + if !matches!(resource, Builder | Alerter | System,) && !seperated.resource_types.contains(&resource) { seperated.resource_types.push(resource); diff --git a/bin/core/src/requests/read/update.rs b/bin/core/src/requests/read/update.rs index c1332d33a..6d534b5fa 100644 --- a/bin/core/src/requests/read/update.rs +++ b/bin/core/src/requests/read/update.rs @@ -1,34 +1,73 @@ use async_trait::async_trait; use monitor_types::{ - entities::{build::Build, update::Update}, - requests::read::ListUpdates, + entities::{ + alerter::Alerter, build::Build, builder::Builder, deployment::Deployment, repo::Repo, + server::Server, + }, + requests::read::{ListUpdates, ListUpdatesResponse}, }; use mungos::mongodb::{bson::doc, options::FindOptions}; use resolver_api::Resolve; use crate::{auth::RequestUser, resource::Resource, state::State}; +const UPDATES_PER_PAGE: i64 = 20; + #[async_trait] impl Resolve for State { async fn resolve( &self, - ListUpdates { query }: ListUpdates, + ListUpdates { query, page }: ListUpdates, user: RequestUser, - ) -> anyhow::Result> { - if user.is_admin { - let updates = self - .db - .updates - .get_some( - query, - FindOptions::builder().sort(doc! { "ts": -1 }).build(), - ) - .await?; - Ok(updates) + ) -> anyhow::Result { + let query = if user.is_admin { + query } else { + let server_ids = + >::get_resource_ids_for_non_admin(self, &user.id).await?; + let deployment_ids = + >::get_resource_ids_for_non_admin(self, &user.id) + .await?; let build_ids = >::get_resource_ids_for_non_admin(self, &user.id).await?; - todo!() - } + let repo_ids = + >::get_resource_ids_for_non_admin(self, &user.id).await?; + let builder_ids = + >::get_resource_ids_for_non_admin(self, &user.id) + .await?; + let alerter_ids = + >::get_resource_ids_for_non_admin(self, &user.id) + .await?; + let mut query = query.unwrap_or_default(); + query.extend(doc! { + "$or": [ + { "target.type": "Server", "target.id": { "$in": &server_ids } }, + { "target.type": "Deployment", "target.id": { "$in": &deployment_ids } }, + { "target.type": "Build", "target.id": { "$in": &build_ids } }, + { "target.type": "Repo", "target.id": { "$in": &repo_ids } }, + { "target.type": "Builder", "target.id": { "$in": &builder_ids } }, + { "target.type": "Alerter", "target.id": { "$in": &alerter_ids } }, + ] + }); + query.into() + }; + let updates = self + .db + .updates + .get_some( + query, + FindOptions::builder() + .sort(doc! { "ts": -1 }) + .skip(page as u64 * UPDATES_PER_PAGE as u64) + .limit(UPDATES_PER_PAGE) + .build(), + ) + .await?; + let next_page = if updates.len() == UPDATES_PER_PAGE as usize { + Some(page + 1) + } else { + None + }; + Ok(ListUpdatesResponse { updates, next_page }) } } diff --git a/client/ts/src/responses.ts b/client/ts/src/responses.ts index b0ba33bad..5d4ca3551 100644 --- a/client/ts/src/responses.ts +++ b/client/ts/src/responses.ts @@ -66,7 +66,7 @@ export type ReadResponses = { ListTags: Types.CustomTag[]; // ==== UPDATE ==== - ListUpdates: Types.Update[]; + ListUpdates: Types.ListUpdatesResponse; // ==== SERVER STATS ==== GetAllSystemStats: Types.AllSystemStats; diff --git a/client/ts/src/types.ts b/client/ts/src/types.ts index 04699c0a5..74f7f9404 100644 --- a/client/ts/src/types.ts +++ b/client/ts/src/types.ts @@ -918,6 +918,7 @@ export type Tag = }}; export interface FindResources { + search: string; tags: Tag[]; } @@ -1033,6 +1034,12 @@ export interface ListTags { export interface ListUpdates { query?: MongoDocument; + page?: number; +} + +export interface ListUpdatesResponse { + updates: Update[]; + next_page?: number; } export type PartialAlerterConfig = diff --git a/lib/types/src/requests/read/search.rs b/lib/types/src/requests/read/search.rs index 27c9028d0..be74f7555 100644 --- a/lib/types/src/requests/read/search.rs +++ b/lib/types/src/requests/read/search.rs @@ -12,6 +12,7 @@ use super::{BuildListItem, DeploymentListItem, RepoListItem, ServerListItem}; #[derive(Serialize, Deserialize, Debug, Clone, Request)] #[response(FindResourcesResponse)] pub struct FindResources { + pub search: String, pub tags: Vec, } diff --git a/lib/types/src/requests/read/update.rs b/lib/types/src/requests/read/update.rs index 4dd6b9583..609abce80 100644 --- a/lib/types/src/requests/read/update.rs +++ b/lib/types/src/requests/read/update.rs @@ -6,7 +6,16 @@ use crate::{entities::update::Update, MongoDocument}; #[typeshare] #[derive(Serialize, Deserialize, Debug, Clone, Request)] -#[response(Vec)] +#[response(ListUpdatesResponse)] pub struct ListUpdates { pub query: Option, + #[serde(default)] + pub page: u32, +} + +#[typeshare] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ListUpdatesResponse { + pub updates: Vec, + pub next_page: Option }