mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
cargo fmt
This commit is contained in:
parent
66e087787a
commit
63e600d49e
|
@ -8,7 +8,7 @@ use serde_json;
|
||||||
// use uuid;
|
// use uuid;
|
||||||
|
|
||||||
use audit::AuditScope;
|
use audit::AuditScope;
|
||||||
use entry::{Entry, EntryValid, EntryNew, EntryCommitted};
|
use entry::{Entry, EntryCommitted, EntryNew, EntryValid};
|
||||||
use filter::Filter;
|
use filter::Filter;
|
||||||
|
|
||||||
mod idl;
|
mod idl;
|
||||||
|
@ -53,7 +53,11 @@ pub trait BackendReadTransaction {
|
||||||
fn get_conn(&self) -> &r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager>;
|
fn get_conn(&self) -> &r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager>;
|
||||||
|
|
||||||
// Take filter, and AuditScope ref?
|
// Take filter, and AuditScope ref?
|
||||||
fn search(&self, au: &mut AuditScope, filt: &Filter) -> Result<Vec<Entry<EntryValid, EntryCommitted>>, BackendError> {
|
fn search(
|
||||||
|
&self,
|
||||||
|
au: &mut AuditScope,
|
||||||
|
filt: &Filter,
|
||||||
|
) -> Result<Vec<Entry<EntryValid, EntryCommitted>>, BackendError> {
|
||||||
// Do things
|
// Do things
|
||||||
// Alloc a vec for the entries.
|
// Alloc a vec for the entries.
|
||||||
// FIXME: Make this actually a good size for the result set ...
|
// FIXME: Make this actually a good size for the result set ...
|
||||||
|
@ -97,7 +101,8 @@ pub trait BackendReadTransaction {
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|id_ent| {
|
.filter_map(|id_ent| {
|
||||||
// TODO: Should we do better than unwrap?
|
// TODO: Should we do better than unwrap?
|
||||||
let mut e: Entry<EntryValid, EntryCommitted> = serde_json::from_str(id_ent.data.as_str()).unwrap();
|
let mut e: Entry<EntryValid, EntryCommitted> =
|
||||||
|
serde_json::from_str(id_ent.data.as_str()).unwrap();
|
||||||
e.id = Some(id_ent.id);
|
e.id = Some(id_ent.id);
|
||||||
if e.entry_match_no_index(&filt) {
|
if e.entry_match_no_index(&filt) {
|
||||||
Some(e)
|
Some(e)
|
||||||
|
@ -206,10 +211,14 @@ impl BackendWriteTransaction {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_id2entry_max_id(&self) -> i64 {
|
fn get_id2entry_max_id(&self) -> i64 {
|
||||||
let mut stmt = self.conn.prepare("SELECT MAX(id) as id_max FROM id2entry").unwrap();
|
let mut stmt = self
|
||||||
|
.conn
|
||||||
|
.prepare("SELECT MAX(id) as id_max FROM id2entry")
|
||||||
|
.unwrap();
|
||||||
assert!(stmt.exists(NO_PARAMS).unwrap());
|
assert!(stmt.exists(NO_PARAMS).unwrap());
|
||||||
|
|
||||||
let i: Option<i64> = stmt.query_row(NO_PARAMS, |row| row.get(0))
|
let i: Option<i64> = stmt
|
||||||
|
.query_row(NO_PARAMS, |row| row.get(0))
|
||||||
.expect("failed to execute");
|
.expect("failed to execute");
|
||||||
match i {
|
match i {
|
||||||
Some(e) => e,
|
Some(e) => e,
|
||||||
|
@ -217,7 +226,11 @@ impl BackendWriteTransaction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(&self, au: &mut AuditScope, entries: &Vec<Entry<EntryValid, EntryNew>>) -> Result<(), BackendError> {
|
pub fn create(
|
||||||
|
&self,
|
||||||
|
au: &mut AuditScope,
|
||||||
|
entries: &Vec<Entry<EntryValid, EntryNew>>,
|
||||||
|
) -> Result<(), BackendError> {
|
||||||
audit_segment!(au, || {
|
audit_segment!(au, || {
|
||||||
// Start be audit timer
|
// Start be audit timer
|
||||||
|
|
||||||
|
@ -273,7 +286,11 @@ impl BackendWriteTransaction {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn modify(&self, au: &mut AuditScope, entries: &Vec<Entry<EntryValid, EntryCommitted>>) -> Result<(), BackendError> {
|
pub fn modify(
|
||||||
|
&self,
|
||||||
|
au: &mut AuditScope,
|
||||||
|
entries: &Vec<Entry<EntryValid, EntryCommitted>>,
|
||||||
|
) -> Result<(), BackendError> {
|
||||||
if entries.is_empty() {
|
if entries.is_empty() {
|
||||||
// TODO: Better error
|
// TODO: Better error
|
||||||
return Err(BackendError::EmptyRequest);
|
return Err(BackendError::EmptyRequest);
|
||||||
|
@ -291,7 +308,7 @@ impl BackendWriteTransaction {
|
||||||
data: serde_json::to_string(&e).unwrap(),
|
data: serde_json::to_string(&e).unwrap(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
None => None
|
None => None,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -307,20 +324,25 @@ impl BackendWriteTransaction {
|
||||||
// Now, given the list of id's, update them
|
// Now, given the list of id's, update them
|
||||||
{
|
{
|
||||||
// TODO: ACTUALLY HANDLE THIS ERROR WILLIAM YOU LAZY SHIT.
|
// TODO: ACTUALLY HANDLE THIS ERROR WILLIAM YOU LAZY SHIT.
|
||||||
let mut stmt = self.conn.prepare("UPDATE id2entry SET data = :data WHERE id = :id").unwrap();
|
let mut stmt = self
|
||||||
|
.conn
|
||||||
|
.prepare("UPDATE id2entry SET data = :data WHERE id = :id")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
ser_entries.iter().for_each(|ser_ent| {
|
ser_entries.iter().for_each(|ser_ent| {
|
||||||
stmt.execute_named(&[
|
stmt.execute_named(&[(":id", &ser_ent.id), (":data", &ser_ent.data)])
|
||||||
(":id", &ser_ent.id),
|
.unwrap();
|
||||||
(":data", &ser_ent.data),
|
|
||||||
]).unwrap();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete(&self, au: &mut AuditScope, entries: &Vec<Entry<EntryValid, EntryCommitted>>) -> Result<(), BackendError> {
|
pub fn delete(
|
||||||
|
&self,
|
||||||
|
au: &mut AuditScope,
|
||||||
|
entries: &Vec<Entry<EntryValid, EntryCommitted>>,
|
||||||
|
) -> Result<(), BackendError> {
|
||||||
// Perform a search for the entries --> This is a problem for the caller
|
// Perform a search for the entries --> This is a problem for the caller
|
||||||
|
|
||||||
if entries.is_empty() {
|
if entries.is_empty() {
|
||||||
|
@ -329,11 +351,7 @@ impl BackendWriteTransaction {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assert the Id's exist on the entry.
|
// Assert the Id's exist on the entry.
|
||||||
let id_list: Vec<i64> = entries.iter()
|
let id_list: Vec<i64> = entries.iter().filter_map(|entry| entry.id).collect();
|
||||||
.filter_map(|entry| {
|
|
||||||
entry.id
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Simple: If the list of id's is not the same as the input list, we are missing id's
|
// Simple: If the list of id's is not the same as the input list, we are missing id's
|
||||||
// TODO: This check won't be needed once I rebuild the entry state types.
|
// TODO: This check won't be needed once I rebuild the entry state types.
|
||||||
|
@ -348,7 +366,10 @@ impl BackendWriteTransaction {
|
||||||
// probably okay with this.
|
// probably okay with this.
|
||||||
|
|
||||||
// TODO: ACTUALLY HANDLE THIS ERROR WILLIAM YOU LAZY SHIT.
|
// TODO: ACTUALLY HANDLE THIS ERROR WILLIAM YOU LAZY SHIT.
|
||||||
let mut stmt = self.conn.prepare("DELETE FROM id2entry WHERE id = :id").unwrap();
|
let mut stmt = self
|
||||||
|
.conn
|
||||||
|
.prepare("DELETE FROM id2entry WHERE id = :id")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
id_list.iter().for_each(|id| {
|
id_list.iter().for_each(|id| {
|
||||||
stmt.execute(&[id]).unwrap();
|
stmt.execute(&[id]).unwrap();
|
||||||
|
@ -532,7 +553,7 @@ mod tests {
|
||||||
extern crate tokio;
|
extern crate tokio;
|
||||||
|
|
||||||
use super::super::audit::AuditScope;
|
use super::super::audit::AuditScope;
|
||||||
use super::super::entry::{Entry, EntryInvalid, EntryValid, EntryNew, EntryCommitted};
|
use super::super::entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid};
|
||||||
use super::super::filter::Filter;
|
use super::super::filter::Filter;
|
||||||
use super::{
|
use super::{
|
||||||
Backend, BackendError, BackendReadTransaction, BackendTransaction, BackendWriteTransaction,
|
Backend, BackendError, BackendReadTransaction, BackendTransaction, BackendWriteTransaction,
|
||||||
|
@ -560,7 +581,7 @@ mod tests {
|
||||||
let filt = ei.filter_from_attrs(&vec![String::from("userid")]).unwrap();
|
let filt = ei.filter_from_attrs(&vec![String::from("userid")]).unwrap();
|
||||||
let entries = $be.search($audit, &filt).unwrap();
|
let entries = $be.search($audit, &filt).unwrap();
|
||||||
entries.first().is_some()
|
entries.first().is_some()
|
||||||
}}
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! entry_attr_pres {
|
macro_rules! entry_attr_pres {
|
||||||
|
@ -569,12 +590,10 @@ mod tests {
|
||||||
let filt = ei.filter_from_attrs(&vec![String::from("userid")]).unwrap();
|
let filt = ei.filter_from_attrs(&vec![String::from("userid")]).unwrap();
|
||||||
let entries = $be.search($audit, &filt).unwrap();
|
let entries = $be.search($audit, &filt).unwrap();
|
||||||
match entries.first() {
|
match entries.first() {
|
||||||
Some(ent) => {
|
Some(ent) => ent.attribute_pres($attr),
|
||||||
ent.attribute_pres($attr)
|
None => false,
|
||||||
}
|
}
|
||||||
None => false
|
}};
|
||||||
}
|
|
||||||
}}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -625,7 +644,9 @@ mod tests {
|
||||||
assert!(entry_exists!(audit, be, e2));
|
assert!(entry_exists!(audit, be, e2));
|
||||||
|
|
||||||
// You need to now retrieve the entries back out to get the entry id's
|
// You need to now retrieve the entries back out to get the entry id's
|
||||||
let mut results = be.search(audit, &Filter::Pres(String::from("userid"))).unwrap();
|
let mut results = be
|
||||||
|
.search(audit, &Filter::Pres(String::from("userid")))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Get these out to usable entries.
|
// Get these out to usable entries.
|
||||||
let r1 = results.remove(0);
|
let r1 = results.remove(0);
|
||||||
|
@ -689,9 +710,10 @@ mod tests {
|
||||||
assert!(entry_exists!(audit, be, e2));
|
assert!(entry_exists!(audit, be, e2));
|
||||||
assert!(entry_exists!(audit, be, e3));
|
assert!(entry_exists!(audit, be, e3));
|
||||||
|
|
||||||
|
|
||||||
// You need to now retrieve the entries back out to get the entry id's
|
// You need to now retrieve the entries back out to get the entry id's
|
||||||
let mut results = be.search(audit, &Filter::Pres(String::from("userid"))).unwrap();
|
let mut results = be
|
||||||
|
.search(audit, &Filter::Pres(String::from("userid")))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Get these out to usable entries.
|
// Get these out to usable entries.
|
||||||
let r1 = results.remove(0);
|
let r1 = results.remove(0);
|
||||||
|
@ -727,7 +749,6 @@ mod tests {
|
||||||
// delete none (no entries left)
|
// delete none (no entries left)
|
||||||
// see fn delete for why this is ok, not err
|
// see fn delete for why this is ok, not err
|
||||||
assert!(be.delete(audit, &vec![r2.clone(), r3.clone()]).is_ok());
|
assert!(be.delete(audit, &vec![r2.clone(), r3.clone()]).is_ok());
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
108
src/lib/entry.rs
108
src/lib/entry.rs
|
@ -1,14 +1,14 @@
|
||||||
// use serde_json::{Error, Value};
|
// use serde_json::{Error, Value};
|
||||||
use super::proto_v1::Entry as ProtoEntry;
|
use super::proto_v1::Entry as ProtoEntry;
|
||||||
|
use error::SchemaError;
|
||||||
use filter::Filter;
|
use filter::Filter;
|
||||||
|
use modify::{Modify, ModifyList};
|
||||||
|
use schema::{SchemaAttribute, SchemaClass, SchemaReadTransaction};
|
||||||
use std::collections::btree_map::{Iter as BTreeIter, IterMut as BTreeIterMut};
|
use std::collections::btree_map::{Iter as BTreeIter, IterMut as BTreeIterMut};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::slice::Iter as SliceIter;
|
|
||||||
use modify::{Modify, ModifyList};
|
|
||||||
use schema::{SchemaReadTransaction, SchemaAttribute, SchemaClass};
|
|
||||||
use error::SchemaError;
|
|
||||||
use std::iter::ExactSizeIterator;
|
use std::iter::ExactSizeIterator;
|
||||||
|
use std::slice::Iter as SliceIter;
|
||||||
|
|
||||||
// make a trait entry for everything to adhere to?
|
// make a trait entry for everything to adhere to?
|
||||||
// * How to get indexs out?
|
// * How to get indexs out?
|
||||||
|
@ -175,10 +175,18 @@ impl Entry<EntryInvalid, EntryNew> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<STATE> Entry<EntryInvalid, STATE> {
|
impl<STATE> Entry<EntryInvalid, STATE> {
|
||||||
pub fn validate(self, schema: &SchemaReadTransaction) -> Result<Entry<EntryValid, STATE>, SchemaError> {
|
pub fn validate(
|
||||||
|
self,
|
||||||
|
schema: &SchemaReadTransaction,
|
||||||
|
) -> Result<Entry<EntryValid, STATE>, SchemaError> {
|
||||||
// We need to clone before we start, as well be mutating content.
|
// We need to clone before we start, as well be mutating content.
|
||||||
// We destructure:
|
// We destructure:
|
||||||
let Entry { valid, state, id, attrs } = self;
|
let Entry {
|
||||||
|
valid,
|
||||||
|
state,
|
||||||
|
id,
|
||||||
|
attrs,
|
||||||
|
} = self;
|
||||||
|
|
||||||
let schema_classes = schema.get_classes();
|
let schema_classes = schema.get_classes();
|
||||||
let schema_attributes = schema.get_attributes();
|
let schema_attributes = schema.get_attributes();
|
||||||
|
@ -232,20 +240,16 @@ impl<STATE> Entry<EntryInvalid, STATE> {
|
||||||
{
|
{
|
||||||
// First, check we have class on the object ....
|
// First, check we have class on the object ....
|
||||||
if !ne.attribute_pres("class") {
|
if !ne.attribute_pres("class") {
|
||||||
return Err(SchemaError::InvalidClass)
|
return Err(SchemaError::InvalidClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry_classes = ne.classes();
|
let entry_classes = ne.classes();
|
||||||
let entry_classes_size = entry_classes.len();
|
let entry_classes_size = entry_classes.len();
|
||||||
|
|
||||||
let classes: HashMap<String, &SchemaClass> = entry_classes
|
let classes: HashMap<String, &SchemaClass> = entry_classes
|
||||||
.filter_map(|c| {
|
.filter_map(|c| match schema_classes.get(c) {
|
||||||
match schema_classes.get(c) {
|
Some(cls) => Some((c.clone(), cls)),
|
||||||
Some(cls) => {
|
|
||||||
Some((c.clone(), cls))
|
|
||||||
}
|
|
||||||
None => None,
|
None => None,
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -253,7 +257,6 @@ impl<STATE> Entry<EntryInvalid, STATE> {
|
||||||
return Err(SchemaError::InvalidClass);
|
return Err(SchemaError::InvalidClass);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let extensible = classes.contains_key("extensibleobject");
|
let extensible = classes.contains_key("extensibleobject");
|
||||||
|
|
||||||
// What this is really doing is taking a set of classes, and building an
|
// What this is really doing is taking a set of classes, and building an
|
||||||
|
@ -287,9 +290,7 @@ impl<STATE> Entry<EntryInvalid, STATE> {
|
||||||
for (attr_name, _attr) in must {
|
for (attr_name, _attr) in must {
|
||||||
let avas = ne.get_ava(&attr_name);
|
let avas = ne.get_ava(&attr_name);
|
||||||
if avas.is_none() {
|
if avas.is_none() {
|
||||||
return Err(SchemaError::MissingMustAttribute(
|
return Err(SchemaError::MissingMustAttribute(String::from(attr_name)));
|
||||||
String::from(attr_name)
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +305,7 @@ impl<STATE> Entry<EntryInvalid, STATE> {
|
||||||
// We have to destructure here to make type checker happy
|
// We have to destructure here to make type checker happy
|
||||||
match r {
|
match r {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => return Err(e)
|
Err(e) => return Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
@ -322,7 +323,8 @@ impl<STATE> Entry<EntryInvalid, STATE> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<VALID, STATE> Clone for Entry<VALID, STATE>
|
impl<VALID, STATE> Clone for Entry<VALID, STATE>
|
||||||
where VALID: Copy,
|
where
|
||||||
|
VALID: Copy,
|
||||||
STATE: Copy,
|
STATE: Copy,
|
||||||
{
|
{
|
||||||
// Dirty modifiable state. Works on any other state to dirty them.
|
// Dirty modifiable state. Works on any other state to dirty them.
|
||||||
|
@ -381,7 +383,7 @@ impl<STATE> Entry<EntryValid, STATE> {
|
||||||
valid: EntryInvalid,
|
valid: EntryInvalid,
|
||||||
state: self.state,
|
state: self.state,
|
||||||
id: self.id,
|
id: self.id,
|
||||||
attrs: self.attrs
|
attrs: self.attrs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,7 +392,7 @@ impl<STATE> Entry<EntryValid, STATE> {
|
||||||
valid: self.valid,
|
valid: self.valid,
|
||||||
state: EntryCommitted,
|
state: EntryCommitted,
|
||||||
id: self.id,
|
id: self.id,
|
||||||
attrs: self.attrs
|
attrs: self.attrs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,34 +402,28 @@ impl<STATE> Entry<EntryValid, STATE> {
|
||||||
// This is recursive!!!!
|
// This is recursive!!!!
|
||||||
match filter {
|
match filter {
|
||||||
Filter::Eq(attr, value) => self.attribute_equality(attr.as_str(), value.as_str()),
|
Filter::Eq(attr, value) => self.attribute_equality(attr.as_str(), value.as_str()),
|
||||||
Filter::Sub(attr, subvalue) => self.attribute_substring(attr.as_str(), subvalue.as_str()),
|
Filter::Sub(attr, subvalue) => {
|
||||||
|
self.attribute_substring(attr.as_str(), subvalue.as_str())
|
||||||
|
}
|
||||||
Filter::Pres(attr) => {
|
Filter::Pres(attr) => {
|
||||||
// Given attr, is is present in the entry?
|
// Given attr, is is present in the entry?
|
||||||
self.attribute_pres(attr.as_str())
|
self.attribute_pres(attr.as_str())
|
||||||
}
|
}
|
||||||
Filter::Or(l) => {
|
Filter::Or(l) => l.iter().fold(false, |acc, f| {
|
||||||
l.iter()
|
|
||||||
.fold(false, |acc, f| {
|
|
||||||
if acc {
|
if acc {
|
||||||
acc
|
acc
|
||||||
} else {
|
} else {
|
||||||
self.entry_match_no_index(f)
|
self.entry_match_no_index(f)
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
}
|
Filter::And(l) => l.iter().fold(true, |acc, f| {
|
||||||
Filter::And(l) => {
|
|
||||||
l.iter()
|
|
||||||
.fold(true, |acc, f| {
|
|
||||||
if acc {
|
if acc {
|
||||||
self.entry_match_no_index(f)
|
self.entry_match_no_index(f)
|
||||||
} else {
|
} else {
|
||||||
acc
|
acc
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
}
|
Filter::Not(f) => !self.entry_match_no_index(f),
|
||||||
Filter::Not(f) => {
|
|
||||||
!self.entry_match_no_index(f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,8 +469,7 @@ impl<STATE> Entry<EntryValid, STATE> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_modlist_assert(&self, schema: &SchemaReadTransaction) -> Result<ModifyList, ()>
|
pub fn gen_modlist_assert(&self, schema: &SchemaReadTransaction) -> Result<ModifyList, ()> {
|
||||||
{
|
|
||||||
// Create a modlist from this entry. We make this assuming we want the entry
|
// Create a modlist from this entry. We make this assuming we want the entry
|
||||||
// to have this one as a subset of values. This means if we have single
|
// to have this one as a subset of values. This means if we have single
|
||||||
// values, we'll replace, if they are multivalue, we present them.
|
// values, we'll replace, if they are multivalue, we present them.
|
||||||
|
@ -490,9 +485,7 @@ impl<STATE> Entry<EntryValid, STATE> {
|
||||||
mods.push_mod(Modify::Purged(k.clone()));
|
mods.push_mod(Modify::Purged(k.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => return Err(()),
|
||||||
return Err(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for v in vs {
|
for v in vs {
|
||||||
mods.push_mod(Modify::Present(k.clone(), v.clone()));
|
mods.push_mod(Modify::Present(k.clone(), v.clone()));
|
||||||
|
@ -535,7 +528,11 @@ impl<VALID, STATE> Entry<VALID, STATE> {
|
||||||
// Get the class vec, if any?
|
// Get the class vec, if any?
|
||||||
// How do we indicate "empty?"
|
// How do we indicate "empty?"
|
||||||
// FIXME: Actually handle this error ...
|
// FIXME: Actually handle this error ...
|
||||||
let v = self.attrs.get("class").map(|c| c.len()).expect("INVALID STATE, NO CLASS FOUND");
|
let v = self
|
||||||
|
.attrs
|
||||||
|
.get("class")
|
||||||
|
.map(|c| c.len())
|
||||||
|
.expect("INVALID STATE, NO CLASS FOUND");
|
||||||
let c = self.attrs.get("class").map(|c| c.iter());
|
let c = self.attrs.get("class").map(|c| c.iter());
|
||||||
EntryClasses { size: v, inner: c }
|
EntryClasses { size: v, inner: c }
|
||||||
}
|
}
|
||||||
|
@ -548,7 +545,8 @@ impl<VALID, STATE> Entry<VALID, STATE> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<STATE> Entry<EntryInvalid, STATE>
|
impl<STATE> Entry<EntryInvalid, STATE>
|
||||||
where STATE: Copy,
|
where
|
||||||
|
STATE: Copy,
|
||||||
{
|
{
|
||||||
// This should always work? It's only on validate that we'll build
|
// This should always work? It's only on validate that we'll build
|
||||||
// a list of syntax violations ...
|
// a list of syntax violations ...
|
||||||
|
@ -589,8 +587,7 @@ impl<STATE> Entry<EntryInvalid, STATE>
|
||||||
v.remove(idx);
|
v.remove(idx);
|
||||||
}
|
}
|
||||||
// It does not exist, move on.
|
// It does not exist, move on.
|
||||||
Err(_) => {
|
Err(_) => {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -618,8 +615,7 @@ impl<STATE> Entry<EntryInvalid, STATE>
|
||||||
// This is effectively clone-and-transform
|
// This is effectively clone-and-transform
|
||||||
|
|
||||||
// clone the entry
|
// clone the entry
|
||||||
let mut ne: Entry<EntryInvalid, STATE> =
|
let mut ne: Entry<EntryInvalid, STATE> = Entry {
|
||||||
Entry {
|
|
||||||
valid: self.valid,
|
valid: self.valid,
|
||||||
state: self.state,
|
state: self.state,
|
||||||
id: self.id,
|
id: self.id,
|
||||||
|
@ -629,15 +625,9 @@ impl<STATE> Entry<EntryInvalid, STATE>
|
||||||
// mutate
|
// mutate
|
||||||
for modify in modlist.mods.iter() {
|
for modify in modlist.mods.iter() {
|
||||||
match modify {
|
match modify {
|
||||||
Modify::Present(a, v) => {
|
Modify::Present(a, v) => ne.add_ava(a.clone(), v.clone()),
|
||||||
ne.add_ava(a.clone(), v.clone())
|
Modify::Removed(a, v) => ne.remove_ava(a, v),
|
||||||
}
|
Modify::Purged(a) => ne.purge_ava(a),
|
||||||
Modify::Removed(a, v) => {
|
|
||||||
ne.remove_ava(a, v)
|
|
||||||
}
|
|
||||||
Modify::Purged(a) => {
|
|
||||||
ne.purge_ava(a)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -745,16 +735,16 @@ mod tests {
|
||||||
let mut e: Entry<EntryInvalid, EntryNew> = Entry::new();
|
let mut e: Entry<EntryInvalid, EntryNew> = Entry::new();
|
||||||
e.add_ava(String::from("userid"), String::from("william"));
|
e.add_ava(String::from("userid"), String::from("william"));
|
||||||
|
|
||||||
let mods = ModifyList::new_list(vec![
|
let mods = ModifyList::new_list(vec![Modify::Present(
|
||||||
Modify::Present(String::from("attr"), String::from("value")),
|
String::from("attr"),
|
||||||
]);
|
String::from("value"),
|
||||||
|
)]);
|
||||||
|
|
||||||
let ne = e.apply_modlist(&mods).unwrap();
|
let ne = e.apply_modlist(&mods).unwrap();
|
||||||
|
|
||||||
// Assert the changes are there
|
// Assert the changes are there
|
||||||
assert!(ne.attribute_equality("attr", "value"));
|
assert!(ne.attribute_equality("attr", "value"));
|
||||||
|
|
||||||
|
|
||||||
// Assert present for multivalue
|
// Assert present for multivalue
|
||||||
// Assert purge on single/multi/empty value
|
// Assert purge on single/multi/empty value
|
||||||
// Assert removed on value that exists and doesn't exist
|
// Assert removed on value that exists and doesn't exist
|
||||||
|
|
|
@ -2,7 +2,7 @@ use super::filter::Filter;
|
||||||
use super::proto_v1::Entry as ProtoEntry;
|
use super::proto_v1::Entry as ProtoEntry;
|
||||||
use super::proto_v1::{CreateRequest, Response, SearchRequest, SearchResponse};
|
use super::proto_v1::{CreateRequest, Response, SearchRequest, SearchResponse};
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
use entry::{Entry, EntryInvalid, EntryNew, EntryValid, EntryCommitted};
|
use entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid};
|
||||||
use error::OperationError;
|
use error::OperationError;
|
||||||
use modify::ModifyList;
|
use modify::ModifyList;
|
||||||
|
|
||||||
|
@ -185,4 +185,3 @@ impl ModifyEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
// in parallel map/reduce style, or directly on a single
|
// in parallel map/reduce style, or directly on a single
|
||||||
// entry to assert it matches.
|
// entry to assert it matches.
|
||||||
|
|
||||||
use std::cmp::{Ordering, PartialOrd};
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
use std::cmp::{Ordering, PartialOrd};
|
||||||
|
|
||||||
// Perhaps make these json serialisable. Certainly would make parsing
|
// Perhaps make these json serialisable. Certainly would make parsing
|
||||||
// simpler ...
|
// simpler ...
|
||||||
|
@ -102,7 +102,7 @@ impl PartialOrd for Filter {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::Filter;
|
use super::Filter;
|
||||||
use entry::{Entry, EntryValid, EntryNew};
|
use entry::{Entry, EntryNew, EntryValid};
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use std::cmp::{Ordering, PartialOrd};
|
use std::cmp::{Ordering, PartialOrd};
|
||||||
|
|
||||||
|
@ -199,14 +199,17 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_or_entry_filter() {
|
fn test_or_entry_filter() {
|
||||||
let e: Entry<EntryValid, EntryNew> = serde_json::from_str(r#"{
|
let e: Entry<EntryValid, EntryNew> = serde_json::from_str(
|
||||||
|
r#"{
|
||||||
"valid": null,
|
"valid": null,
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"userid": ["william"],
|
"userid": ["william"],
|
||||||
"uidNumber": ["1000"]
|
"uidNumber": ["1000"]
|
||||||
}
|
}
|
||||||
}"#).unwrap();
|
}"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let f_t1a = Filter::Or(vec![
|
let f_t1a = Filter::Or(vec![
|
||||||
Filter::Eq(String::from("userid"), String::from("william")),
|
Filter::Eq(String::from("userid"), String::from("william")),
|
||||||
|
@ -235,14 +238,17 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_and_entry_filter() {
|
fn test_and_entry_filter() {
|
||||||
let e: Entry<EntryValid, EntryNew> = serde_json::from_str(r#"{
|
let e: Entry<EntryValid, EntryNew> = serde_json::from_str(
|
||||||
|
r#"{
|
||||||
"valid": null,
|
"valid": null,
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"userid": ["william"],
|
"userid": ["william"],
|
||||||
"uidNumber": ["1000"]
|
"uidNumber": ["1000"]
|
||||||
}
|
}
|
||||||
}"#).unwrap();
|
}"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let f_t1a = Filter::And(vec![
|
let f_t1a = Filter::And(vec![
|
||||||
Filter::Eq(String::from("userid"), String::from("william")),
|
Filter::Eq(String::from("userid"), String::from("william")),
|
||||||
|
@ -271,64 +277,80 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_not_entry_filter() {
|
fn test_not_entry_filter() {
|
||||||
let e1: Entry<EntryValid, EntryNew> = serde_json::from_str(r#"{
|
let e1: Entry<EntryValid, EntryNew> = serde_json::from_str(
|
||||||
|
r#"{
|
||||||
"valid": null,
|
"valid": null,
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"userid": ["william"],
|
"userid": ["william"],
|
||||||
"uidNumber": ["1000"]
|
"uidNumber": ["1000"]
|
||||||
}
|
}
|
||||||
}"#).unwrap();
|
}"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let f_t1a = Filter::Not(Box::new(
|
let f_t1a = Filter::Not(Box::new(Filter::Eq(
|
||||||
Filter::Eq(String::from("userid"), String::from("alice")),
|
String::from("userid"),
|
||||||
));
|
String::from("alice"),
|
||||||
|
)));
|
||||||
assert!(e1.entry_match_no_index(&f_t1a));
|
assert!(e1.entry_match_no_index(&f_t1a));
|
||||||
|
|
||||||
let f_t2a = Filter::Not(Box::new(
|
let f_t2a = Filter::Not(Box::new(Filter::Eq(
|
||||||
Filter::Eq(String::from("userid"), String::from("william")),
|
String::from("userid"),
|
||||||
));
|
String::from("william"),
|
||||||
|
)));
|
||||||
assert!(!e1.entry_match_no_index(&f_t2a));
|
assert!(!e1.entry_match_no_index(&f_t2a));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_nested_entry_filter() {
|
fn test_nested_entry_filter() {
|
||||||
let e1: Entry<EntryValid, EntryNew> = serde_json::from_str(r#"{
|
let e1: Entry<EntryValid, EntryNew> = serde_json::from_str(
|
||||||
|
r#"{
|
||||||
"valid": null,
|
"valid": null,
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["person"],
|
"class": ["person"],
|
||||||
"uidNumber": ["1000"]
|
"uidNumber": ["1000"]
|
||||||
}
|
}
|
||||||
}"#).unwrap();
|
}"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let e2: Entry<EntryValid, EntryNew> = serde_json::from_str(r#"{
|
let e2: Entry<EntryValid, EntryNew> = serde_json::from_str(
|
||||||
|
r#"{
|
||||||
"valid": null,
|
"valid": null,
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["person"],
|
"class": ["person"],
|
||||||
"uidNumber": ["1001"]
|
"uidNumber": ["1001"]
|
||||||
}
|
}
|
||||||
}"#).unwrap();
|
}"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let e3: Entry<EntryValid, EntryNew> = serde_json::from_str(r#"{
|
let e3: Entry<EntryValid, EntryNew> = serde_json::from_str(
|
||||||
|
r#"{
|
||||||
"valid": null,
|
"valid": null,
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["person"],
|
"class": ["person"],
|
||||||
"uidNumber": ["1002"]
|
"uidNumber": ["1002"]
|
||||||
}
|
}
|
||||||
}"#).unwrap();
|
}"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let e4: Entry<EntryValid, EntryNew> = serde_json::from_str(r#"{
|
let e4: Entry<EntryValid, EntryNew> = serde_json::from_str(
|
||||||
|
r#"{
|
||||||
"valid": null,
|
"valid": null,
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["group"],
|
"class": ["group"],
|
||||||
"uidNumber": ["1000"]
|
"uidNumber": ["1000"]
|
||||||
}
|
}
|
||||||
}"#).unwrap();
|
}"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let f_t1a = Filter::And(vec![
|
let f_t1a = Filter::And(vec![
|
||||||
Filter::Eq(String::from("class"), String::from("person")),
|
Filter::Eq(String::from("class"), String::from("person")),
|
||||||
|
|
|
@ -39,10 +39,10 @@ mod constants;
|
||||||
mod entry;
|
mod entry;
|
||||||
mod event;
|
mod event;
|
||||||
mod identity;
|
mod identity;
|
||||||
|
mod modify;
|
||||||
mod plugins;
|
mod plugins;
|
||||||
mod schema;
|
mod schema;
|
||||||
mod server;
|
mod server;
|
||||||
mod modify;
|
|
||||||
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod core;
|
pub mod core;
|
||||||
|
|
|
@ -133,7 +133,7 @@ mod tests {
|
||||||
|
|
||||||
use audit::AuditScope;
|
use audit::AuditScope;
|
||||||
use be::{Backend, BackendWriteTransaction};
|
use be::{Backend, BackendWriteTransaction};
|
||||||
use entry::{Entry, EntryValid, EntryInvalid, EntryNew};
|
use entry::{Entry, EntryInvalid, EntryNew, EntryValid};
|
||||||
use event::CreateEvent;
|
use event::CreateEvent;
|
||||||
use schema::{Schema, SchemaWriteTransaction};
|
use schema::{Schema, SchemaWriteTransaction};
|
||||||
|
|
||||||
|
|
|
@ -75,3 +75,23 @@ impl CreateRequest {
|
||||||
//
|
//
|
||||||
// On loginSuccess, we send a cookie, and that allows the token to be
|
// On loginSuccess, we send a cookie, and that allows the token to be
|
||||||
// generated. The cookie can be shared between servers.
|
// generated. The cookie can be shared between servers.
|
||||||
|
|
||||||
|
// Request auth for identity X
|
||||||
|
pub struct AuthRequest {}
|
||||||
|
|
||||||
|
// Respond with the list of auth types and nonce, etc.
|
||||||
|
pub struct AuthResponse {}
|
||||||
|
|
||||||
|
// Provide responses
|
||||||
|
pub struct AuthProvide {}
|
||||||
|
|
||||||
|
// After authprovide, we can move to AuthResponse (for more)
|
||||||
|
// or below ...
|
||||||
|
|
||||||
|
// Go away.
|
||||||
|
// Provide reason?
|
||||||
|
pub struct AuthDenied {}
|
||||||
|
|
||||||
|
// Welcome friend.
|
||||||
|
// On success provide entry "self", for group assertions?
|
||||||
|
pub struct AuthSuccess {}
|
||||||
|
|
|
@ -5,11 +5,11 @@ use super::error::SchemaError;
|
||||||
use super::filter::Filter;
|
use super::filter::Filter;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
// Apparently this is nightly only?
|
// Apparently this is nightly only?
|
||||||
|
use modify::ModifyList;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use modify::ModifyList;
|
|
||||||
|
|
||||||
use concread::cowcell::{CowCell, CowCellReadTxn, CowCellWriteTxn};
|
use concread::cowcell::{CowCell, CowCellReadTxn, CowCellWriteTxn};
|
||||||
|
|
||||||
|
@ -917,9 +917,7 @@ impl SchemaInner {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Filter::Not(filter) => {
|
Filter::Not(filter) => self.validate_filter(filter),
|
||||||
self.validate_filter(filter)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -932,9 +930,7 @@ impl SchemaInner {
|
||||||
|
|
||||||
fn is_multivalue(&self, attr_name: &str) -> Result<bool, SchemaError> {
|
fn is_multivalue(&self, attr_name: &str) -> Result<bool, SchemaError> {
|
||||||
match self.attributes.get(attr_name) {
|
match self.attributes.get(attr_name) {
|
||||||
Some(a_schema) => {
|
Some(a_schema) => Ok(a_schema.multivalue),
|
||||||
Ok(a_schema.multivalue)
|
|
||||||
}
|
|
||||||
None => {
|
None => {
|
||||||
return Err(SchemaError::InvalidAttribute);
|
return Err(SchemaError::InvalidAttribute);
|
||||||
}
|
}
|
||||||
|
@ -1009,7 +1005,7 @@ impl Schema {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::super::audit::AuditScope;
|
use super::super::audit::AuditScope;
|
||||||
use super::super::constants::*;
|
use super::super::constants::*;
|
||||||
use super::super::entry::{Entry, EntryValid, EntryInvalid, EntryNew};
|
use super::super::entry::{Entry, EntryInvalid, EntryNew, EntryValid};
|
||||||
use super::super::error::SchemaError;
|
use super::super::error::SchemaError;
|
||||||
use super::super::filter::Filter;
|
use super::super::filter::Filter;
|
||||||
use super::{IndexType, Schema, SchemaAttribute, SchemaClass, SyntaxType};
|
use super::{IndexType, Schema, SchemaAttribute, SchemaClass, SyntaxType};
|
||||||
|
@ -1238,10 +1234,7 @@ mod tests {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(e_no_class.validate(&schema), Err(SchemaError::InvalidClass));
|
||||||
e_no_class.validate(&schema),
|
|
||||||
Err(SchemaError::InvalidClass)
|
|
||||||
);
|
|
||||||
|
|
||||||
let e_bad_class: Entry<EntryInvalid, EntryNew> = serde_json::from_str(
|
let e_bad_class: Entry<EntryInvalid, EntryNew> = serde_json::from_str(
|
||||||
r#"{
|
r#"{
|
||||||
|
|
|
@ -10,15 +10,16 @@ use be::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use constants::{JSON_ANONYMOUS_V1, JSON_SYSTEM_INFO_V1};
|
use constants::{JSON_ANONYMOUS_V1, JSON_SYSTEM_INFO_V1};
|
||||||
use entry::{Entry, EntryNew, EntryCommitted, EntryValid, EntryInvalid};
|
use entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid};
|
||||||
use error::{OperationError, SchemaError};
|
use error::{OperationError, SchemaError};
|
||||||
use event::{CreateEvent, ExistsEvent, OpResult, SearchEvent, SearchResult, DeleteEvent, ModifyEvent};
|
use event::{
|
||||||
|
CreateEvent, DeleteEvent, ExistsEvent, ModifyEvent, OpResult, SearchEvent, SearchResult,
|
||||||
|
};
|
||||||
use filter::Filter;
|
use filter::Filter;
|
||||||
use log::EventLog;
|
use log::EventLog;
|
||||||
use plugins::Plugins;
|
|
||||||
use schema::{Schema, SchemaTransaction, SchemaReadTransaction, SchemaWriteTransaction};
|
|
||||||
use modify::ModifyList;
|
use modify::ModifyList;
|
||||||
|
use plugins::Plugins;
|
||||||
|
use schema::{Schema, SchemaReadTransaction, SchemaTransaction, SchemaWriteTransaction};
|
||||||
|
|
||||||
pub fn start(log: actix::Addr<EventLog>, path: &str, threads: usize) -> actix::Addr<QueryServer> {
|
pub fn start(log: actix::Addr<EventLog>, path: &str, threads: usize) -> actix::Addr<QueryServer> {
|
||||||
let mut audit = AuditScope::new("server_start");
|
let mut audit = AuditScope::new("server_start");
|
||||||
|
@ -89,7 +90,11 @@ pub trait QueryServerReadTransaction {
|
||||||
|
|
||||||
fn get_be_txn(&self) -> &Self::BackendTransactionType;
|
fn get_be_txn(&self) -> &Self::BackendTransactionType;
|
||||||
|
|
||||||
fn search(&self, au: &mut AuditScope, se: &SearchEvent) -> Result<Vec<Entry<EntryValid, EntryCommitted>>, OperationError> {
|
fn search(
|
||||||
|
&self,
|
||||||
|
au: &mut AuditScope,
|
||||||
|
se: &SearchEvent,
|
||||||
|
) -> Result<Vec<Entry<EntryValid, EntryCommitted>>, OperationError> {
|
||||||
// TODO: Validate the filter
|
// TODO: Validate the filter
|
||||||
// This is an important security step because it prevents us from
|
// This is an important security step because it prevents us from
|
||||||
// performing un-indexed searches on attr's that don't exist in the
|
// performing un-indexed searches on attr's that don't exist in the
|
||||||
|
@ -141,8 +146,11 @@ pub trait QueryServerReadTransaction {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn internal_search(&self, audit: &mut AuditScope, filter: Filter) -> Result<Vec<Entry<EntryValid, EntryCommitted>>, OperationError> {
|
fn internal_search(
|
||||||
|
&self,
|
||||||
|
audit: &mut AuditScope,
|
||||||
|
filter: Filter,
|
||||||
|
) -> Result<Vec<Entry<EntryValid, EntryCommitted>>, OperationError> {
|
||||||
let mut audit_int = AuditScope::new("internal_search");
|
let mut audit_int = AuditScope::new("internal_search");
|
||||||
let se = SearchEvent::new_internal(filter);
|
let se = SearchEvent::new_internal(filter);
|
||||||
let res = self.search(&mut audit_int, &se);
|
let res = self.search(&mut audit_int, &se);
|
||||||
|
@ -240,7 +248,8 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
// based on request size in the frontend?
|
// based on request size in the frontend?
|
||||||
|
|
||||||
// Copy the entries to a writeable form.
|
// Copy the entries to a writeable form.
|
||||||
let mut candidates: Vec<Entry<EntryInvalid, EntryNew>> = ce.entries.iter().map(|er| er.clone()).collect();
|
let mut candidates: Vec<Entry<EntryInvalid, EntryNew>> =
|
||||||
|
ce.entries.iter().map(|er| er.clone()).collect();
|
||||||
|
|
||||||
// run any pre plugins, giving them the list of mutable candidates.
|
// run any pre plugins, giving them the list of mutable candidates.
|
||||||
// pre-plugins are defined here in their correct order of calling!
|
// pre-plugins are defined here in their correct order of calling!
|
||||||
|
@ -261,15 +270,13 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
return plug_pre_res;
|
return plug_pre_res;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (norm_cand, invalid_cand):
|
let (norm_cand, invalid_cand): (
|
||||||
(Vec<Result<Entry<EntryValid, EntryNew>, _>>,
|
Vec<Result<Entry<EntryValid, EntryNew>, _>>,
|
||||||
Vec<Result<_, SchemaError>>) = candidates.into_iter()
|
Vec<Result<_, SchemaError>>,
|
||||||
.map(|e| {
|
) = candidates
|
||||||
e.validate(&self.schema)
|
.into_iter()
|
||||||
})
|
.map(|e| e.validate(&self.schema))
|
||||||
.partition(|e| {
|
.partition(|e| e.is_ok());
|
||||||
e.is_ok()
|
|
||||||
});
|
|
||||||
|
|
||||||
for err in invalid_cand.iter() {
|
for err in invalid_cand.iter() {
|
||||||
audit_log!(au, "Schema Violation: {:?}", err);
|
audit_log!(au, "Schema Violation: {:?}", err);
|
||||||
|
@ -279,14 +286,11 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
return Err(OperationError::SchemaViolation);
|
return Err(OperationError::SchemaViolation);
|
||||||
}
|
}
|
||||||
|
|
||||||
let norm_cand: Vec<Entry<EntryValid, EntryNew>> = norm_cand.into_iter()
|
let norm_cand: Vec<Entry<EntryValid, EntryNew>> = norm_cand
|
||||||
.map(|e| {
|
.into_iter()
|
||||||
match e {
|
.map(|e| match e {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(_) => {
|
Err(_) => panic!("Invalid data set state!!!"),
|
||||||
panic!("Invalid data set state!!!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -319,7 +323,6 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn delete(&self, au: &mut AuditScope, ce: &DeleteEvent) -> Result<(), OperationError> {
|
pub fn delete(&self, au: &mut AuditScope, ce: &DeleteEvent) -> Result<(), OperationError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
@ -340,19 +343,17 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if pre_candidates.len() == 0 {
|
if pre_candidates.len() == 0 {
|
||||||
return Err(OperationError::NoMatchingEntries)
|
return Err(OperationError::NoMatchingEntries);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Clone a set of writeables.
|
// Clone a set of writeables.
|
||||||
// Apply the modlist -> Remember, we have a set of origs
|
// Apply the modlist -> Remember, we have a set of origs
|
||||||
// and the new modified ents.
|
// and the new modified ents.
|
||||||
let mut candidates: Vec<Entry<EntryInvalid, EntryCommitted>> = pre_candidates.into_iter()
|
let mut candidates: Vec<Entry<EntryInvalid, EntryCommitted>> = pre_candidates
|
||||||
|
.into_iter()
|
||||||
.map(|er| {
|
.map(|er| {
|
||||||
// TODO: Deal with this properly william
|
// TODO: Deal with this properly william
|
||||||
er
|
er.invalidate().apply_modlist(&me.modlist).unwrap()
|
||||||
.invalidate()
|
|
||||||
.apply_modlist(&me.modlist)
|
|
||||||
.unwrap()
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -364,15 +365,13 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
// FIXME: This normalisation COPIES everything, which may be
|
// FIXME: This normalisation COPIES everything, which may be
|
||||||
// slow.
|
// slow.
|
||||||
|
|
||||||
let (norm_cand, invalid_cand):
|
let (norm_cand, invalid_cand): (
|
||||||
(Vec<Result<Entry<EntryValid, EntryCommitted>, _>>,
|
Vec<Result<Entry<EntryValid, EntryCommitted>, _>>,
|
||||||
Vec<Result<_, SchemaError>>) = candidates.into_iter()
|
Vec<Result<_, SchemaError>>,
|
||||||
.map(|e| {
|
) = candidates
|
||||||
e.validate(&self.schema)
|
.into_iter()
|
||||||
})
|
.map(|e| e.validate(&self.schema))
|
||||||
.partition(|e| {
|
.partition(|e| e.is_ok());
|
||||||
e.is_ok()
|
|
||||||
});
|
|
||||||
|
|
||||||
for err in invalid_cand.iter() {
|
for err in invalid_cand.iter() {
|
||||||
audit_log!(au, "Schema Violation: {:?}", err);
|
audit_log!(au, "Schema Violation: {:?}", err);
|
||||||
|
@ -382,14 +381,11 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
return Err(OperationError::SchemaViolation);
|
return Err(OperationError::SchemaViolation);
|
||||||
}
|
}
|
||||||
|
|
||||||
let norm_cand: Vec<Entry<EntryValid, EntryCommitted>> = norm_cand.into_iter()
|
let norm_cand: Vec<Entry<EntryValid, EntryCommitted>> = norm_cand
|
||||||
.map(|e| {
|
.into_iter()
|
||||||
match e {
|
.map(|e| match e {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(_) => {
|
Err(_) => panic!("Invalid data set state!!!"),
|
||||||
panic!("Invalid data set state!!!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -442,7 +438,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
pub fn internal_delete(
|
pub fn internal_delete(
|
||||||
&self,
|
&self,
|
||||||
audit: &mut AuditScope,
|
audit: &mut AuditScope,
|
||||||
filter: Filter
|
filter: Filter,
|
||||||
) -> Result<(), OperationError> {
|
) -> Result<(), OperationError> {
|
||||||
let mut audit_int = AuditScope::new("internal_delete");
|
let mut audit_int = AuditScope::new("internal_delete");
|
||||||
let de = DeleteEvent::new_internal(filter);
|
let de = DeleteEvent::new_internal(filter);
|
||||||
|
@ -455,7 +451,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
&self,
|
&self,
|
||||||
audit: &mut AuditScope,
|
audit: &mut AuditScope,
|
||||||
filter: Filter,
|
filter: Filter,
|
||||||
modlist: ModifyList
|
modlist: ModifyList,
|
||||||
) -> Result<(), OperationError> {
|
) -> Result<(), OperationError> {
|
||||||
let mut audit_int = AuditScope::new("internal_modify");
|
let mut audit_int = AuditScope::new("internal_modify");
|
||||||
let me = ModifyEvent::new_internal(filter, modlist);
|
let me = ModifyEvent::new_internal(filter, modlist);
|
||||||
|
@ -470,7 +466,10 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
// and markers. They act as though they have the highest level privilege
|
// and markers. They act as though they have the highest level privilege
|
||||||
// IE there are no access control checks.
|
// IE there are no access control checks.
|
||||||
|
|
||||||
pub fn internal_exists_or_create(&self, e: Entry<EntryValid, EntryNew>) -> Result<(), OperationError> {
|
pub fn internal_exists_or_create(
|
||||||
|
&self,
|
||||||
|
e: Entry<EntryValid, EntryNew>,
|
||||||
|
) -> Result<(), OperationError> {
|
||||||
// If the thing exists, stop.
|
// If the thing exists, stop.
|
||||||
// if not, create from Entry.
|
// if not, create from Entry.
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
|
@ -549,9 +548,6 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
self.internal_create(audit, vec![e.invalidate()])
|
self.internal_create(audit, vec![e.invalidate()])
|
||||||
} else if results.len() == 1 {
|
} else if results.len() == 1 {
|
||||||
// it exists. To guarantee content exactly as is, we compare if it's identical.
|
// it exists. To guarantee content exactly as is, we compare if it's identical.
|
||||||
audit_log!(audit, "LEFT -> {:?}", &e);
|
|
||||||
audit_log!(audit, "RIGHT -> {:?}", &results[0]);
|
|
||||||
|
|
||||||
if !e.compare(&results[0]) {
|
if !e.compare(&results[0]) {
|
||||||
self.internal_delete(audit, filt);
|
self.internal_delete(audit, filt);
|
||||||
self.internal_create(audit, vec![e.invalidate()]);
|
self.internal_create(audit, vec![e.invalidate()]);
|
||||||
|
@ -715,7 +711,7 @@ mod tests {
|
||||||
|
|
||||||
use super::super::audit::AuditScope;
|
use super::super::audit::AuditScope;
|
||||||
use super::super::be::{Backend, BackendTransaction};
|
use super::super::be::{Backend, BackendTransaction};
|
||||||
use super::super::entry::{Entry, EntryNew, EntryCommitted, EntryValid, EntryInvalid};
|
use super::super::entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid};
|
||||||
use super::super::event::{CreateEvent, SearchEvent};
|
use super::super::event::{CreateEvent, SearchEvent};
|
||||||
use super::super::filter::Filter;
|
use super::super::filter::Filter;
|
||||||
use super::super::log;
|
use super::super::log;
|
||||||
|
@ -791,9 +787,7 @@ mod tests {
|
||||||
println!("--> {:?}", r2);
|
println!("--> {:?}", r2);
|
||||||
assert!(r2.len() == 1);
|
assert!(r2.len() == 1);
|
||||||
|
|
||||||
let expected = unsafe {
|
let expected = unsafe { vec![e.to_valid_committed()] };
|
||||||
vec![e.to_valid_committed()]
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(r2, expected);
|
assert_eq!(r2, expected);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue