|
@@ -1,5 +1,7 @@
|
|
|
use std::cmp::Ordering;
|
|
|
|
|
|
+use aspect_ident::DeviceIdent;
|
|
|
+use chrono::NaiveDateTime;
|
|
|
use sea_orm::prelude::*;
|
|
|
use sea_orm::{
|
|
|
ActiveValue, EntityOrSelect, IntoActiveModel, QueryOrder, QuerySelect, TransactionTrait,
|
|
@@ -7,7 +9,7 @@ use sea_orm::{
|
|
|
use tracing::*;
|
|
|
|
|
|
use aspect_ident::device::{self, EquivocationReport};
|
|
|
-use aspect_sqldb::device as sqldevice;
|
|
|
+use aspect_sqldb::{device as sqldevice, user_device};
|
|
|
use aspect_util::codec;
|
|
|
use aspect_util::prelude::*;
|
|
|
|
|
@@ -60,11 +62,7 @@ impl DeviceDatastore {
|
|
|
/// If we have a "better" entry in the database (like a device record with
|
|
|
/// a higher sequence number) or construct one (like an equivocation report
|
|
|
/// from trying to insert a conflicting DIR, we return that instead).
|
|
|
- pub async fn try_insert_dir_entry(
|
|
|
- &self,
|
|
|
- dir: &DirEntry,
|
|
|
- user_id: Option<i32>,
|
|
|
- ) -> Result<Option<DirEntry>, Error> {
|
|
|
+ pub async fn try_insert_dir_entry(&self, dir: &DirEntry) -> Result<Option<DirEntry>, Error> {
|
|
|
// TODO try to flatten this function out a bit
|
|
|
|
|
|
let ident = dir.ident();
|
|
@@ -89,7 +87,6 @@ impl DeviceDatastore {
|
|
|
device_id: ActiveValue::Set(ident_raw),
|
|
|
seqno: ActiveValue::Set(seqno),
|
|
|
is_equivocation: ActiveValue::Set(new_is_equiv),
|
|
|
- owner_user_id: ActiveValue::Set(user_id),
|
|
|
// don't set record yet so we can refer to dir_enc later
|
|
|
..Default::default()
|
|
|
};
|
|
@@ -218,7 +215,7 @@ impl DeviceDatastore {
|
|
|
&self,
|
|
|
id: &device::DeviceIdent,
|
|
|
) -> Result<Option<DirEntry>, Error> {
|
|
|
- let idbuf = id.as_ref().to_vec();
|
|
|
+ let idbuf = id.to_vec();
|
|
|
|
|
|
let m = sqldevice::Entity::find()
|
|
|
.filter(sqldevice::Column::DeviceId.eq(idbuf))
|
|
@@ -232,23 +229,81 @@ impl DeviceDatastore {
|
|
|
Ok(Some(ent))
|
|
|
}
|
|
|
|
|
|
+ /// Adds a device to a user if not already registered.
|
|
|
+ pub async fn add_device_to_user(
|
|
|
+ &self,
|
|
|
+ id: &device::DeviceIdent,
|
|
|
+ uid: i32,
|
|
|
+ ) -> Result<(), Error> {
|
|
|
+ let idbuf = id.to_vec();
|
|
|
+ let tx = self.dbc.begin().await?;
|
|
|
+
|
|
|
+ let found = user_device::Entity::find()
|
|
|
+ .filter(user_device::Column::DeviceId.eq(idbuf.clone()))
|
|
|
+ .limit(1)
|
|
|
+ .one(&tx)
|
|
|
+ .await?;
|
|
|
+
|
|
|
+ // If it's already registered then we should report who registered them.
|
|
|
+ if let Some(found_m) = found {
|
|
|
+ return Err(Error::DeviceAlreadyClaimed(*id, found_m.user_id));
|
|
|
+ }
|
|
|
+
|
|
|
+ let user_device_am = user_device::ActiveModel {
|
|
|
+ user_id: ActiveValue::Set(uid),
|
|
|
+ device_id: ActiveValue::Set(id.to_vec()),
|
|
|
+ added: ActiveValue::Set(get_now_ndt()),
|
|
|
+ ..Default::default()
|
|
|
+ };
|
|
|
+
|
|
|
+ user_device_am.insert(&tx).await?;
|
|
|
+
|
|
|
+ tx.commit().await?;
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
+
|
|
|
/// Reports all of the valid device entries, returning the most recent
|
|
|
- /// instances of each. If `local` is set then only reports devices that
|
|
|
- /// correspond to users in the database, but does not report which users
|
|
|
- /// they correspond to.
|
|
|
+ /// instances of each.
|
|
|
pub async fn dump_valid_devices(&self, local: bool) -> Result<Vec<DirEntry>, Error> {
|
|
|
// TODO add a range parameter
|
|
|
|
|
|
- let clause = if local {
|
|
|
- sqldevice::Column::OwnerUserId
|
|
|
- .is_not_null()
|
|
|
- .and(sqldevice::Column::IsMostRecentKnown.eq(true))
|
|
|
- .and(sqldevice::Column::IsEquivocation.eq(false))
|
|
|
- } else {
|
|
|
- sqldevice::Column::IsMostRecentKnown
|
|
|
- .eq(true)
|
|
|
- .and(sqldevice::Column::IsEquivocation.eq(false))
|
|
|
- };
|
|
|
+ if local {
|
|
|
+ warn!("queried for local devices but we don't support this directly anymore");
|
|
|
+ }
|
|
|
+
|
|
|
+ let clause = sqldevice::Column::IsMostRecentKnown
|
|
|
+ .eq(true)
|
|
|
+ .and(sqldevice::Column::IsEquivocation.eq(false));
|
|
|
+
|
|
|
+ let mm = sqldevice::Entity::find()
|
|
|
+ .filter(clause)
|
|
|
+ .all(&self.dbc)
|
|
|
+ .await?;
|
|
|
+
|
|
|
+ let mut ents = Vec::new();
|
|
|
+ for m in mm {
|
|
|
+ // TODO Skip invalid devices?
|
|
|
+ ents.push(codec::decode::<DirEntry>(&m.record)?);
|
|
|
+ }
|
|
|
+
|
|
|
+ Ok(ents)
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Reports all of the valid device entries, returning the most recent
|
|
|
+ /// instances of each in some range.
|
|
|
+ pub async fn dump_valid_devices_range(
|
|
|
+ &self,
|
|
|
+ start: DeviceIdent,
|
|
|
+ end: DeviceIdent,
|
|
|
+ ) -> Result<Vec<DirEntry>, Error> {
|
|
|
+ let clause = sqldevice::Column::DeviceId
|
|
|
+ .gte(start.to_vec())
|
|
|
+ .add(sqldevice::Column::DeviceId.lt(end.to_vec()))
|
|
|
+ .and(
|
|
|
+ sqldevice::Column::IsMostRecentKnown
|
|
|
+ .eq(true)
|
|
|
+ .and(sqldevice::Column::IsEquivocation.eq(false)),
|
|
|
+ );
|
|
|
|
|
|
let mm = sqldevice::Entity::find()
|
|
|
.filter(clause)
|
|
@@ -257,9 +312,14 @@ impl DeviceDatastore {
|
|
|
|
|
|
let mut ents = Vec::new();
|
|
|
for m in mm {
|
|
|
+ // TODO Skip invalid devices?
|
|
|
ents.push(codec::decode::<DirEntry>(&m.record)?);
|
|
|
}
|
|
|
|
|
|
Ok(ents)
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+fn get_now_ndt() -> NaiveDateTime {
|
|
|
+ chrono::Utc::now().naive_utc()
|
|
|
+}
|