paginated list updates

This commit is contained in:
mbecker20
2023-07-29 04:08:36 -04:00
parent 482f8bb862
commit 26c692978a
6 changed files with 93 additions and 31 deletions
+19 -13
View File
@@ -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<FindResources, RequestUser> for State {
async fn resolve(
&self,
FindResources { tags }: FindResources,
FindResources { search, tags }: FindResources,
user: RequestUser,
) -> anyhow::Result<FindResourcesResponse> {
let SeperateTags {
@@ -34,7 +34,16 @@ impl Resolve<FindResources, RequestUser> 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<FindResources, RequestUser> for State {
.context("failed to parse server id as ObjectId")
})
.collect::<anyhow::Result<Vec<_>>>()?;
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<FindResources, RequestUser> 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<Tag>) -> 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);
+55 -16
View File
@@ -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<ListUpdates, RequestUser> for State {
async fn resolve(
&self,
ListUpdates { query }: ListUpdates,
ListUpdates { query, page }: ListUpdates,
user: RequestUser,
) -> anyhow::Result<Vec<Update>> {
if user.is_admin {
let updates = self
.db
.updates
.get_some(
query,
FindOptions::builder().sort(doc! { "ts": -1 }).build(),
)
.await?;
Ok(updates)
) -> anyhow::Result<ListUpdatesResponse> {
let query = if user.is_admin {
query
} else {
let server_ids =
<State as Resource<Server>>::get_resource_ids_for_non_admin(self, &user.id).await?;
let deployment_ids =
<State as Resource<Deployment>>::get_resource_ids_for_non_admin(self, &user.id)
.await?;
let build_ids =
<State as Resource<Build>>::get_resource_ids_for_non_admin(self, &user.id).await?;
todo!()
}
let repo_ids =
<State as Resource<Repo>>::get_resource_ids_for_non_admin(self, &user.id).await?;
let builder_ids =
<State as Resource<Builder>>::get_resource_ids_for_non_admin(self, &user.id)
.await?;
let alerter_ids =
<State as Resource<Alerter>>::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 })
}
}
+1 -1
View File
@@ -66,7 +66,7 @@ export type ReadResponses = {
ListTags: Types.CustomTag[];
// ==== UPDATE ====
ListUpdates: Types.Update[];
ListUpdates: Types.ListUpdatesResponse;
// ==== SERVER STATS ====
GetAllSystemStats: Types.AllSystemStats;
+7
View File
@@ -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 =
+1
View File
@@ -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<Tag>,
}
+10 -1
View File
@@ -6,7 +6,16 @@ use crate::{entities::update::Update, MongoDocument};
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone, Request)]
#[response(Vec<Update>)]
#[response(ListUpdatesResponse)]
pub struct ListUpdates {
pub query: Option<MongoDocument>,
#[serde(default)]
pub page: u32,
}
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ListUpdatesResponse {
pub updates: Vec<Update>,
pub next_page: Option<u32>
}