feat(backend): Phase 2.5 permission and share models
This commit is contained in:
parent
3eeef6d9c8
commit
eb0e2cc4b5
7 changed files with 265 additions and 106 deletions
|
|
@ -1,9 +1,19 @@
|
|||
pub mod user;
|
||||
pub mod family;
|
||||
pub mod profile;
|
||||
pub mod health_data;
|
||||
pub mod lab_result;
|
||||
pub mod medication;
|
||||
pub mod appointment;
|
||||
### /home/asoliver/desarrollo/normogen/./backend/src/models/mod.rs
|
||||
```rust
|
||||
1: pub mod user;
|
||||
2: pub mod family;
|
||||
3: pub mod profile;
|
||||
4: pub mod health_data;
|
||||
5: pub mod lab_result;
|
||||
6: pub mod medication;
|
||||
7: pub mod appointment;
|
||||
8: pub mod share;
|
||||
9: pub mod refresh_token;
|
||||
```
|
||||
|
||||
pub mod permission;
|
||||
pub mod share;
|
||||
pub mod refresh_token;
|
||||
|
||||
pub use permission::Permission;
|
||||
pub use share::Share;
|
||||
pub use share::ShareRepository;
|
||||
|
|
|
|||
33
backend/src/models/permission.rs
Normal file
33
backend/src/models/permission.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use strum::{Display, EnumString};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Display, EnumString)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[strum(serialize_all = "lowercase")]
|
||||
pub enum Permission {
|
||||
Read,
|
||||
Write,
|
||||
Delete,
|
||||
Share,
|
||||
Admin,
|
||||
}
|
||||
|
||||
impl Permission {
|
||||
pub fn can_read(&self) -> bool {
|
||||
matches!(self, Self::Read | Self::Admin)
|
||||
}
|
||||
|
||||
pub fn can_write(&self) -> bool {
|
||||
matches!(self, Self::Write | Self::Admin)
|
||||
}
|
||||
|
||||
pub fn can_delete(&self) -> bool {
|
||||
matches!(self, Self::Delete | Self::Admin)
|
||||
}
|
||||
|
||||
pub fn can_share(&self) -> bool {
|
||||
matches!(self, Self::Share | Self::Admin)
|
||||
}
|
||||
}
|
||||
|
||||
pub type Permissions = Vec<Permission>;
|
||||
|
|
@ -1,24 +1,111 @@
|
|||
use bson::doc;
|
||||
use mongodb::Collection;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use mongodb::bson::{oid::ObjectId, DateTime};
|
||||
use wither::{
|
||||
bson::{oid::ObjectId},
|
||||
Model,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
use super::permission::Permission;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Model)]
|
||||
#[model(collection_name="shares")]
|
||||
pub struct Share {
|
||||
#[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
|
||||
pub id: Option<ObjectId>,
|
||||
#[serde(rename = "shareId")]
|
||||
pub share_id: String,
|
||||
#[serde(rename = "userId")]
|
||||
pub user_id: String,
|
||||
#[serde(rename = "encryptedDataKey")]
|
||||
pub encrypted_data_key: String,
|
||||
#[serde(rename = "dataKeyIv")]
|
||||
pub data_key_iv: String,
|
||||
#[serde(rename = "dataKeyAuthTag")]
|
||||
pub data_key_auth_tag: String,
|
||||
#[serde(rename = "expiresAt")]
|
||||
pub expires_at: DateTime,
|
||||
#[serde(rename = "createdAt")]
|
||||
pub created_at: DateTime,
|
||||
#[serde(rename = "accessCount")]
|
||||
pub access_count: i32,
|
||||
pub owner_id: ObjectId,
|
||||
pub target_user_id: ObjectId,
|
||||
pub resource_type: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub resource_id: Option<ObjectId>,
|
||||
pub permissions: Vec<Permission>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub expires_at: Option<chrono::DateTime<chrono::Utc>>,
|
||||
pub created_at: chrono::DateTime<chrono::Utc>,
|
||||
pub active: bool,
|
||||
}
|
||||
|
||||
impl Share {
|
||||
pub fn new(
|
||||
owner_id: ObjectId,
|
||||
target_user_id: ObjectId,
|
||||
resource_type: String,
|
||||
resource_id: Option<ObjectId>,
|
||||
permissions: Vec<Permission>,
|
||||
expires_at: Option<chrono::DateTime<chrono::Utc>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
id: None,
|
||||
owner_id,
|
||||
target_user_id,
|
||||
resource_type,
|
||||
resource_id,
|
||||
permissions,
|
||||
expires_at,
|
||||
created_at: chrono::Utc::now(),
|
||||
active: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_expired(&self) -> bool {
|
||||
if let Some(expires) = self.expires_at {
|
||||
chrono::Utc::now() > expires
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_permission(&self, permission: &Permission) -> bool {
|
||||
self.permissions.contains(permission) || self.permissions.contains(&Permission::Admin)
|
||||
}
|
||||
|
||||
pub fn revoke(&mut self) {
|
||||
self.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ShareRepository {
|
||||
collection: Collection<Share>,
|
||||
}
|
||||
|
||||
impl ShareRepository {
|
||||
pub fn new(collection: Collection<Share>) -> Self {
|
||||
Self { collection }
|
||||
}
|
||||
|
||||
pub async fn create(&self, share: &Share) -> mongodb::error::Result<Option<ObjectId>> {
|
||||
let result = self.collection.insert_one(share, None).await?;
|
||||
Ok(Some(result.inserted_id.as_object_id().unwrap()))
|
||||
}
|
||||
|
||||
pub async fn find_by_id(&self, id: &ObjectId) -> mongodb::error::Result<Option<Share>> {
|
||||
self.collection.find_one(doc! { "_id": id }, None).await
|
||||
}
|
||||
|
||||
pub async fn find_by_owner(&self, owner_id: &ObjectId) -> mongodb::error::Result<Vec<Share>> {
|
||||
self.collection
|
||||
.find(doc! { "owner_id": owner_id }, None)
|
||||
.await
|
||||
.map(|cursor| cursor.collect())
|
||||
.map_err(|e| mongodb::error::Error::from(e))
|
||||
}
|
||||
|
||||
pub async fn find_by_target(&self, target_user_id: &ObjectId) -> mongodb::error::Result<Vec<Share>> {
|
||||
self.collection
|
||||
.find(doc! { "target_user_id": target_user_id, "active": true }, None)
|
||||
.await
|
||||
.map(|cursor| cursor.collect())
|
||||
.map_err(|e| mongodb::error::Error::from(e))
|
||||
}
|
||||
|
||||
pub async fn update(&self, share: &Share) -> mongodb::error::Result<()> {
|
||||
self.collection.replace_one(doc! { "_id": &share.id }, share, None).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete(&self, share_id: &ObjectId) -> mongodb::error::Result<()> {
|
||||
self.collection.delete_one(doc! { "_id": share_id }, None).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue