Add user and device provenance colums
This commit is contained in:
parent
bfb522b2c7
commit
715bbc4d2e
6 changed files with 82 additions and 11 deletions
|
|
@ -143,7 +143,9 @@ impl Database {
|
||||||
document_id as "document_id: Hyphenated",
|
document_id as "document_id: Hyphenated",
|
||||||
relative_path,
|
relative_path,
|
||||||
updated_date as "updated_date: chrono::DateTime<Utc>",
|
updated_date as "updated_date: chrono::DateTime<Utc>",
|
||||||
is_deleted
|
is_deleted,
|
||||||
|
user_id,
|
||||||
|
device_id
|
||||||
from latest_document_versions
|
from latest_document_versions
|
||||||
order by vault_update_id
|
order by vault_update_id
|
||||||
"#,
|
"#,
|
||||||
|
|
@ -175,7 +177,9 @@ impl Database {
|
||||||
document_id as "document_id: Hyphenated",
|
document_id as "document_id: Hyphenated",
|
||||||
relative_path,
|
relative_path,
|
||||||
updated_date as "updated_date: chrono::DateTime<Utc>",
|
updated_date as "updated_date: chrono::DateTime<Utc>",
|
||||||
is_deleted
|
is_deleted,
|
||||||
|
user_id,
|
||||||
|
device_id
|
||||||
from latest_document_versions
|
from latest_document_versions
|
||||||
where vault_update_id > ?
|
where vault_update_id > ?
|
||||||
order by vault_update_id
|
order by vault_update_id
|
||||||
|
|
@ -233,7 +237,9 @@ impl Database {
|
||||||
relative_path,
|
relative_path,
|
||||||
updated_date as "updated_date: chrono::DateTime<Utc>",
|
updated_date as "updated_date: chrono::DateTime<Utc>",
|
||||||
content,
|
content,
|
||||||
is_deleted
|
is_deleted,
|
||||||
|
user_id,
|
||||||
|
device_id
|
||||||
from latest_document_versions
|
from latest_document_versions
|
||||||
where relative_path = ?
|
where relative_path = ?
|
||||||
order by vault_update_id desc -- `latest_document_versions` only contains a single latest version of each document, however,
|
order by vault_update_id desc -- `latest_document_versions` only contains a single latest version of each document, however,
|
||||||
|
|
@ -270,7 +276,9 @@ impl Database {
|
||||||
relative_path,
|
relative_path,
|
||||||
updated_date as "updated_date: chrono::DateTime<Utc>",
|
updated_date as "updated_date: chrono::DateTime<Utc>",
|
||||||
content,
|
content,
|
||||||
is_deleted
|
is_deleted,
|
||||||
|
user_id,
|
||||||
|
device_id
|
||||||
from latest_document_versions
|
from latest_document_versions
|
||||||
where document_id = ?
|
where document_id = ?
|
||||||
"#,
|
"#,
|
||||||
|
|
@ -302,7 +310,9 @@ impl Database {
|
||||||
relative_path,
|
relative_path,
|
||||||
updated_date as "updated_date: chrono::DateTime<Utc>",
|
updated_date as "updated_date: chrono::DateTime<Utc>",
|
||||||
content,
|
content,
|
||||||
is_deleted
|
is_deleted,
|
||||||
|
user_id,
|
||||||
|
device_id
|
||||||
from documents
|
from documents
|
||||||
where vault_update_id = ?"#,
|
where vault_update_id = ?"#,
|
||||||
vault_update_id
|
vault_update_id
|
||||||
|
|
@ -333,16 +343,20 @@ impl Database {
|
||||||
relative_path,
|
relative_path,
|
||||||
updated_date,
|
updated_date,
|
||||||
content,
|
content,
|
||||||
is_deleted
|
is_deleted,
|
||||||
|
user_id,
|
||||||
|
device_id
|
||||||
)
|
)
|
||||||
values (?, ?, ?, ?, ?, ?)
|
values (?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
"#,
|
"#,
|
||||||
version.vault_update_id,
|
version.vault_update_id,
|
||||||
document_id,
|
document_id,
|
||||||
version.relative_path,
|
version.relative_path,
|
||||||
version.updated_date,
|
version.updated_date,
|
||||||
version.content,
|
version.content,
|
||||||
version.is_deleted
|
version.is_deleted,
|
||||||
|
version.user_id,
|
||||||
|
version.device_id
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(transaction) = transaction {
|
if let Some(transaction) = transaction {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE documents ADD COLUMN user_id TEXT NOT NULL DEFAULT "";
|
||||||
|
ALTER TABLE documents ADD COLUMN device_id TEXT NOT NULL DEFAULT "";
|
||||||
|
|
@ -6,6 +6,7 @@ use sync_lib::bytes_to_base64;
|
||||||
pub type VaultId = String;
|
pub type VaultId = String;
|
||||||
pub type VaultUpdateId = i64;
|
pub type VaultUpdateId = i64;
|
||||||
pub type DocumentId = uuid::Uuid;
|
pub type DocumentId = uuid::Uuid;
|
||||||
|
pub type UserId = String;
|
||||||
pub type DeviceId = String;
|
pub type DeviceId = String;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -16,6 +17,8 @@ pub struct StoredDocumentVersion {
|
||||||
pub updated_date: DateTime<Utc>,
|
pub updated_date: DateTime<Utc>,
|
||||||
pub content: Vec<u8>,
|
pub content: Vec<u8>,
|
||||||
pub is_deleted: bool,
|
pub is_deleted: bool,
|
||||||
|
pub user_id: UserId,
|
||||||
|
pub device_id: DeviceId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<Self> for StoredDocumentVersion {
|
impl PartialEq<Self> for StoredDocumentVersion {
|
||||||
|
|
@ -30,6 +33,8 @@ pub struct DocumentVersionWithoutContent {
|
||||||
pub relative_path: String,
|
pub relative_path: String,
|
||||||
pub updated_date: DateTime<Utc>,
|
pub updated_date: DateTime<Utc>,
|
||||||
pub is_deleted: bool,
|
pub is_deleted: bool,
|
||||||
|
pub user_id: UserId,
|
||||||
|
pub device_id: DeviceId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<StoredDocumentVersion> for DocumentVersionWithoutContent {
|
impl From<StoredDocumentVersion> for DocumentVersionWithoutContent {
|
||||||
|
|
@ -40,6 +45,8 @@ impl From<StoredDocumentVersion> for DocumentVersionWithoutContent {
|
||||||
relative_path: value.relative_path,
|
relative_path: value.relative_path,
|
||||||
updated_date: value.updated_date,
|
updated_date: value.updated_date,
|
||||||
is_deleted: value.is_deleted,
|
is_deleted: value.is_deleted,
|
||||||
|
user_id: value.user_id,
|
||||||
|
device_id: value.device_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -53,6 +60,8 @@ pub struct DocumentVersion {
|
||||||
pub updated_date: DateTime<Utc>,
|
pub updated_date: DateTime<Utc>,
|
||||||
pub content_base64: String,
|
pub content_base64: String,
|
||||||
pub is_deleted: bool,
|
pub is_deleted: bool,
|
||||||
|
pub user_id: UserId,
|
||||||
|
pub device_id: DeviceId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<StoredDocumentVersion> for DocumentVersion {
|
impl From<StoredDocumentVersion> for DocumentVersion {
|
||||||
|
|
@ -64,6 +73,8 @@ impl From<StoredDocumentVersion> for DocumentVersion {
|
||||||
updated_date: value.updated_date,
|
updated_date: value.updated_date,
|
||||||
content_base64: bytes_to_base64(&value.content),
|
content_base64: bytes_to_base64(&value.content),
|
||||||
is_deleted: value.is_deleted,
|
is_deleted: value.is_deleted,
|
||||||
|
user_id: value.user_id,
|
||||||
|
device_id: value.device_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
use aide_axum_typed_multipart::TypedMultipart;
|
use aide_axum_typed_multipart::TypedMultipart;
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
use axum::extract::{Path, State};
|
use axum::{
|
||||||
|
Extension,
|
||||||
|
extract::{Path, State},
|
||||||
|
};
|
||||||
|
use axum_extra::{TypedHeader, headers::UserAgent};
|
||||||
use axum_jsonschema::Json;
|
use axum_jsonschema::Json;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
@ -15,6 +19,7 @@ use crate::{
|
||||||
DeviceId, DocumentId, DocumentVersionWithoutContent, StoredDocumentVersion, VaultId,
|
DeviceId, DocumentId, DocumentVersionWithoutContent, StoredDocumentVersion, VaultId,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
config::user_config::User,
|
||||||
errors::{SyncServerError, client_error, server_error},
|
errors::{SyncServerError, client_error, server_error},
|
||||||
utils::{normalize::normalize, sanitize_path::sanitize_path},
|
utils::{normalize::normalize, sanitize_path::sanitize_path},
|
||||||
};
|
};
|
||||||
|
|
@ -32,12 +37,16 @@ pub struct CreateDocumentPathParams {
|
||||||
#[axum::debug_handler]
|
#[axum::debug_handler]
|
||||||
pub async fn create_document_multipart(
|
pub async fn create_document_multipart(
|
||||||
Path(CreateDocumentPathParams { vault_id }): Path<CreateDocumentPathParams>,
|
Path(CreateDocumentPathParams { vault_id }): Path<CreateDocumentPathParams>,
|
||||||
|
Extension(user): Extension<User>,
|
||||||
|
TypedHeader(user_agent): TypedHeader<UserAgent>,
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
TypedMultipart(axum_typed_multipart::TypedMultipart(request)): TypedMultipart<
|
TypedMultipart(axum_typed_multipart::TypedMultipart(request)): TypedMultipart<
|
||||||
CreateDocumentVersionMultipart,
|
CreateDocumentVersionMultipart,
|
||||||
>,
|
>,
|
||||||
) -> Result<Json<DocumentVersionWithoutContent>, SyncServerError> {
|
) -> Result<Json<DocumentVersionWithoutContent>, SyncServerError> {
|
||||||
internal_create_document(
|
internal_create_document(
|
||||||
|
user,
|
||||||
|
user_agent,
|
||||||
state,
|
state,
|
||||||
vault_id,
|
vault_id,
|
||||||
request.document_id,
|
request.document_id,
|
||||||
|
|
@ -54,6 +63,8 @@ pub async fn create_document_multipart(
|
||||||
#[axum::debug_handler]
|
#[axum::debug_handler]
|
||||||
pub async fn create_document_json(
|
pub async fn create_document_json(
|
||||||
Path(CreateDocumentPathParams { vault_id }): Path<CreateDocumentPathParams>,
|
Path(CreateDocumentPathParams { vault_id }): Path<CreateDocumentPathParams>,
|
||||||
|
Extension(user): Extension<User>,
|
||||||
|
TypedHeader(user_agent): TypedHeader<UserAgent>,
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Json(request): Json<CreateDocumentVersion>,
|
Json(request): Json<CreateDocumentVersion>,
|
||||||
) -> Result<Json<DocumentVersionWithoutContent>, SyncServerError> {
|
) -> Result<Json<DocumentVersionWithoutContent>, SyncServerError> {
|
||||||
|
|
@ -62,6 +73,8 @@ pub async fn create_document_json(
|
||||||
.map_err(client_error)?;
|
.map_err(client_error)?;
|
||||||
|
|
||||||
internal_create_document(
|
internal_create_document(
|
||||||
|
user,
|
||||||
|
user_agent,
|
||||||
state,
|
state,
|
||||||
vault_id,
|
vault_id,
|
||||||
request.document_id,
|
request.document_id,
|
||||||
|
|
@ -72,7 +85,10 @@ pub async fn create_document_json(
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
async fn internal_create_document(
|
async fn internal_create_document(
|
||||||
|
user: User,
|
||||||
|
user_agent: UserAgent,
|
||||||
state: AppState,
|
state: AppState,
|
||||||
vault_id: VaultId,
|
vault_id: VaultId,
|
||||||
document_id: Option<DocumentId>,
|
document_id: Option<DocumentId>,
|
||||||
|
|
@ -120,6 +136,8 @@ async fn internal_create_document(
|
||||||
content,
|
content,
|
||||||
updated_date: chrono::Utc::now(),
|
updated_date: chrono::Utc::now(),
|
||||||
is_deleted: false,
|
is_deleted: false,
|
||||||
|
user_id: user.name,
|
||||||
|
device_id: user_agent.to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
state
|
state
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
use axum::extract::{Path, State};
|
use axum::{
|
||||||
|
Extension,
|
||||||
|
extract::{Path, State},
|
||||||
|
};
|
||||||
|
use axum_extra::{TypedHeader, headers::UserAgent};
|
||||||
use axum_jsonschema::Json;
|
use axum_jsonschema::Json;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
@ -13,6 +17,7 @@ use crate::{
|
||||||
DocumentId, DocumentVersionWithoutContent, StoredDocumentVersion, VaultId,
|
DocumentId, DocumentVersionWithoutContent, StoredDocumentVersion, VaultId,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
config::user_config::User,
|
||||||
errors::{SyncServerError, server_error},
|
errors::{SyncServerError, server_error},
|
||||||
utils::{normalize::normalize, sanitize_path::sanitize_path},
|
utils::{normalize::normalize, sanitize_path::sanitize_path},
|
||||||
};
|
};
|
||||||
|
|
@ -32,6 +37,8 @@ pub async fn delete_document(
|
||||||
vault_id,
|
vault_id,
|
||||||
document_id,
|
document_id,
|
||||||
}): Path<DeleteDocumentPathParams>,
|
}): Path<DeleteDocumentPathParams>,
|
||||||
|
Extension(user): Extension<User>,
|
||||||
|
TypedHeader(user_agent): TypedHeader<UserAgent>,
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Json(request): Json<DeleteDocumentVersion>,
|
Json(request): Json<DeleteDocumentVersion>,
|
||||||
) -> Result<Json<DocumentVersionWithoutContent>, SyncServerError> {
|
) -> Result<Json<DocumentVersionWithoutContent>, SyncServerError> {
|
||||||
|
|
@ -54,6 +61,8 @@ pub async fn delete_document(
|
||||||
content: vec![],
|
content: vec![],
|
||||||
updated_date: chrono::Utc::now(),
|
updated_date: chrono::Utc::now(),
|
||||||
is_deleted: true,
|
is_deleted: true,
|
||||||
|
user_id: user.name,
|
||||||
|
device_id: user_agent.to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
state
|
state
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
use aide_axum_typed_multipart::TypedMultipart;
|
use aide_axum_typed_multipart::TypedMultipart;
|
||||||
use anyhow::{Context as _, anyhow};
|
use anyhow::{Context as _, anyhow};
|
||||||
use axum::extract::{Path, State};
|
use axum::{
|
||||||
|
Extension,
|
||||||
|
extract::{Path, State},
|
||||||
|
};
|
||||||
|
use axum_extra::{TypedHeader, headers::UserAgent};
|
||||||
use axum_jsonschema::Json;
|
use axum_jsonschema::Json;
|
||||||
use log::info;
|
use log::info;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
|
|
@ -17,6 +21,7 @@ use crate::{
|
||||||
broadcasts::VaultUpdate,
|
broadcasts::VaultUpdate,
|
||||||
database::models::{DeviceId, DocumentId, StoredDocumentVersion, VaultId, VaultUpdateId},
|
database::models::{DeviceId, DocumentId, StoredDocumentVersion, VaultId, VaultUpdateId},
|
||||||
},
|
},
|
||||||
|
config::user_config::User,
|
||||||
errors::{SyncServerError, client_error, not_found_error, server_error},
|
errors::{SyncServerError, client_error, not_found_error, server_error},
|
||||||
utils::{dedup_paths::dedup_paths, normalize::normalize, sanitize_path::sanitize_path},
|
utils::{dedup_paths::dedup_paths, normalize::normalize, sanitize_path::sanitize_path},
|
||||||
};
|
};
|
||||||
|
|
@ -36,12 +41,16 @@ pub async fn update_document_multipart(
|
||||||
vault_id,
|
vault_id,
|
||||||
document_id,
|
document_id,
|
||||||
}): Path<UpdateDocumentPathParams>,
|
}): Path<UpdateDocumentPathParams>,
|
||||||
|
Extension(user): Extension<User>,
|
||||||
|
TypedHeader(user_agent): TypedHeader<UserAgent>,
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
TypedMultipart(axum_typed_multipart::TypedMultipart(request)): TypedMultipart<
|
TypedMultipart(axum_typed_multipart::TypedMultipart(request)): TypedMultipart<
|
||||||
UpdateDocumentVersionMultipart,
|
UpdateDocumentVersionMultipart,
|
||||||
>,
|
>,
|
||||||
) -> Result<Json<DocumentUpdateResponse>, SyncServerError> {
|
) -> Result<Json<DocumentUpdateResponse>, SyncServerError> {
|
||||||
internal_update_document(
|
internal_update_document(
|
||||||
|
user,
|
||||||
|
user_agent,
|
||||||
state,
|
state,
|
||||||
vault_id,
|
vault_id,
|
||||||
document_id,
|
document_id,
|
||||||
|
|
@ -59,6 +68,8 @@ pub async fn update_document_json(
|
||||||
vault_id,
|
vault_id,
|
||||||
document_id,
|
document_id,
|
||||||
}): Path<UpdateDocumentPathParams>,
|
}): Path<UpdateDocumentPathParams>,
|
||||||
|
Extension(user): Extension<User>,
|
||||||
|
TypedHeader(user_agent): TypedHeader<UserAgent>,
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Json(request): Json<UpdateDocumentVersion>,
|
Json(request): Json<UpdateDocumentVersion>,
|
||||||
) -> Result<Json<DocumentUpdateResponse>, SyncServerError> {
|
) -> Result<Json<DocumentUpdateResponse>, SyncServerError> {
|
||||||
|
|
@ -67,6 +78,8 @@ pub async fn update_document_json(
|
||||||
.map_err(client_error)?;
|
.map_err(client_error)?;
|
||||||
|
|
||||||
internal_update_document(
|
internal_update_document(
|
||||||
|
user,
|
||||||
|
user_agent,
|
||||||
state,
|
state,
|
||||||
vault_id,
|
vault_id,
|
||||||
document_id,
|
document_id,
|
||||||
|
|
@ -80,6 +93,8 @@ pub async fn update_document_json(
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments, clippy::too_many_lines)]
|
#[allow(clippy::too_many_arguments, clippy::too_many_lines)]
|
||||||
async fn internal_update_document(
|
async fn internal_update_document(
|
||||||
|
user: User,
|
||||||
|
user_agent: UserAgent,
|
||||||
state: AppState,
|
state: AppState,
|
||||||
vault_id: VaultId,
|
vault_id: VaultId,
|
||||||
document_id: DocumentId,
|
document_id: DocumentId,
|
||||||
|
|
@ -198,6 +213,8 @@ async fn internal_update_document(
|
||||||
content: merged_content,
|
content: merged_content,
|
||||||
updated_date: chrono::Utc::now(),
|
updated_date: chrono::Utc::now(),
|
||||||
is_deleted: false,
|
is_deleted: false,
|
||||||
|
user_id: user.name,
|
||||||
|
device_id: user_agent.to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
state
|
state
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue