Import upstream v0.16.22, stripped
Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f Enterprise-only files removed or emptied: 63 Enterprise-only snippets removed: 117 in 50 files Dangling module declarations removed: 5 Cargo edits turning enterprise off: 14 Verification: clean Enterprise feature gates left for rebuilt features: 19 in 18 files Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
This commit is contained in:
commit
7dae9b29fd
1650 files changed
+485521
No files matched your search
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use crate::api::query::QueryResponseBuilder;
|
||||
use common::{Server, auth::AccessToken};
|
||||
use jmap_proto::{
|
||||
method::query::{Filter, QueryRequest, QueryResponse},
|
||||
object::principal::{Principal, PrincipalFilter, PrincipalType},
|
||||
types::state::State,
|
||||
};
|
||||
use registry::{
|
||||
schema::{
|
||||
enums::AccountType,
|
||||
prelude::{ObjectType, Permission, Property},
|
||||
},
|
||||
types::EnumImpl,
|
||||
};
|
||||
use std::future::Future;
|
||||
use store::{
|
||||
registry::RegistryQuery,
|
||||
roaring::RoaringBitmap,
|
||||
search::{SearchFilter, SearchQuery},
|
||||
write::SearchIndex,
|
||||
};
|
||||
use trc::AddContext;
|
||||
|
||||
pub trait PrincipalQuery: Sync + Send {
|
||||
fn principal_query(
|
||||
&self,
|
||||
request: QueryRequest<Principal>,
|
||||
access_token: &AccessToken,
|
||||
) -> impl Future<Output = trc::Result<QueryResponse>> + Send;
|
||||
}
|
||||
|
||||
impl PrincipalQuery for Server {
|
||||
async fn principal_query(
|
||||
&self,
|
||||
mut request: QueryRequest<Principal>,
|
||||
access_token: &AccessToken,
|
||||
) -> trc::Result<QueryResponse> {
|
||||
if !self.core.groupware.allow_directory_query
|
||||
&& !access_token.has_permission(Permission::JmapPrincipalQuery)
|
||||
{
|
||||
return Err(trc::JmapEvent::Forbidden
|
||||
.into_err()
|
||||
.details("The administrator has disabled directory queries.".to_string()));
|
||||
}
|
||||
|
||||
let principal_ids = self
|
||||
.registry()
|
||||
.query::<RoaringBitmap>(
|
||||
RegistryQuery::new(ObjectType::Account).with_tenant(access_token.tenant_id()),
|
||||
)
|
||||
.await
|
||||
.caused_by(trc::location!())?;
|
||||
|
||||
let mut filters = Vec::with_capacity(request.filter.len());
|
||||
for cond in std::mem::take(&mut request.filter) {
|
||||
match cond {
|
||||
Filter::Property(cond) => match cond {
|
||||
PrincipalFilter::Name(name) | PrincipalFilter::Email(name) => {
|
||||
filters.push(SearchFilter::is_in_set(
|
||||
match self.account_id_from_email(&name, false).await? {
|
||||
Some(account_id) => {
|
||||
RoaringBitmap::from_sorted_iter([account_id]).unwrap()
|
||||
}
|
||||
None => RoaringBitmap::new(),
|
||||
},
|
||||
));
|
||||
}
|
||||
PrincipalFilter::AccountIds(ids) => {
|
||||
filters.push(SearchFilter::is_in_set(
|
||||
ids.into_iter()
|
||||
.filter_map(|id| {
|
||||
let id = id.document_id();
|
||||
if principal_ids.contains(id) {
|
||||
Some(id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<RoaringBitmap>(),
|
||||
));
|
||||
}
|
||||
PrincipalFilter::Text(text) => {
|
||||
filters.push(SearchFilter::is_in_set(
|
||||
self.registry()
|
||||
.query::<RoaringBitmap>(
|
||||
RegistryQuery::new(ObjectType::Account)
|
||||
.with_tenant(access_token.tenant_id())
|
||||
.text(Property::Text, text),
|
||||
)
|
||||
.await
|
||||
.caused_by(trc::location!())?,
|
||||
));
|
||||
}
|
||||
PrincipalFilter::Type(principal_type) => {
|
||||
let typ = match principal_type {
|
||||
PrincipalType::Individual => AccountType::User,
|
||||
PrincipalType::Group => AccountType::Group,
|
||||
_ => {
|
||||
filters.push(SearchFilter::is_in_set(Default::default()));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
filters.push(SearchFilter::is_in_set(
|
||||
self.registry()
|
||||
.query::<RoaringBitmap>(
|
||||
RegistryQuery::new(ObjectType::Account)
|
||||
.equal(Property::Type, typ.to_id())
|
||||
.with_tenant(access_token.tenant_id()),
|
||||
)
|
||||
.await
|
||||
.caused_by(trc::location!())?,
|
||||
));
|
||||
}
|
||||
other => {
|
||||
return Err(trc::JmapEvent::UnsupportedFilter
|
||||
.into_err()
|
||||
.details(other.to_string()));
|
||||
}
|
||||
},
|
||||
Filter::And => {
|
||||
filters.push(SearchFilter::And);
|
||||
}
|
||||
Filter::Or => {
|
||||
filters.push(SearchFilter::Or);
|
||||
}
|
||||
Filter::Not => {
|
||||
filters.push(SearchFilter::Not);
|
||||
}
|
||||
Filter::Close => {
|
||||
filters.push(SearchFilter::End);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let results = SearchQuery::new(SearchIndex::InMemory)
|
||||
.with_filters(filters)
|
||||
.with_mask(principal_ids)
|
||||
.filter()
|
||||
.into_bitmap();
|
||||
|
||||
let mut response = QueryResponseBuilder::new(
|
||||
results.len() as usize,
|
||||
self.core.jmap.query_max_results,
|
||||
State::Initial,
|
||||
&request,
|
||||
);
|
||||
|
||||
for document_id in results {
|
||||
if !response.add(0, document_id) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
response.build()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user