fix in db and collaborate
This commit is contained in:
+194
-8
@@ -465,6 +465,144 @@ pub async fn public_page(
|
||||
}))
|
||||
}
|
||||
|
||||
async fn commit_public_pad_task_update(
|
||||
state: &SharedState,
|
||||
page: &db::PublishedPage,
|
||||
source_line: usize,
|
||||
checked: bool,
|
||||
) -> Result<(), ApiError> {
|
||||
let pad_id = page.pad_id.ok_or_else(ApiError::not_found_note)?;
|
||||
let room_key = crate::state::AppState::pad_room_key(&page.resource_slug);
|
||||
let channel = state.pad_channel(&page.resource_slug).await;
|
||||
let collaboration_snapshot = db::pad_collaboration_snapshot(&state.db, pad_id).await?;
|
||||
let collaborative_document = state
|
||||
.collaborative_document(
|
||||
&room_key,
|
||||
collaboration_snapshot.content,
|
||||
collaboration_snapshot.owner_map,
|
||||
collaboration_snapshot.revision_id,
|
||||
)
|
||||
.await;
|
||||
let mut document = collaborative_document.lock().await;
|
||||
let Some(next_content) =
|
||||
db::updated_public_task_content(&document.content, source_line, checked)
|
||||
else {
|
||||
return Ok(());
|
||||
};
|
||||
let base_revision_id = document.revision_id;
|
||||
let operation =
|
||||
collab::operation_from_edit(&document.content, &next_content, &document.owner_map);
|
||||
let (content, owner_map) = collab::apply_operation_to_document(
|
||||
&document.content,
|
||||
&document.owner_map,
|
||||
&operation,
|
||||
&[],
|
||||
)
|
||||
.map_err(|_| ApiError::bad_request("The task could not be updated"))?;
|
||||
let (revision_id, updated_at) =
|
||||
db::save_pad_revision(&state.db, pad_id, &content, Some("public"), &owner_map).await?;
|
||||
let update_id = u64::try_from(revision_id).unwrap_or_default().max(1);
|
||||
document.content.clone_from(&content);
|
||||
document.owner_map.clone_from(&owner_map);
|
||||
document.revision_id = revision_id;
|
||||
document.record(AppliedOperation {
|
||||
base_revision_id,
|
||||
revision_id,
|
||||
client_id: "public_task".into(),
|
||||
update_id,
|
||||
operation: operation.clone(),
|
||||
owner_replacements: Vec::new(),
|
||||
});
|
||||
let _ = channel.send(RoomEvent::Document(NoteUpdate {
|
||||
base_revision_id,
|
||||
revision_id,
|
||||
updated_at,
|
||||
author: Some("public".into()),
|
||||
client_id: "public_task".into(),
|
||||
update_id,
|
||||
operation,
|
||||
owner_replacements: Vec::new(),
|
||||
}));
|
||||
drop(document);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn commit_public_note_task_update(
|
||||
state: &SharedState,
|
||||
page: &db::PublishedPage,
|
||||
source_line: usize,
|
||||
checked: bool,
|
||||
) -> Result<(), ApiError> {
|
||||
let note_id = page.note_id.ok_or_else(ApiError::not_found_note)?;
|
||||
let workspace_id = page.workspace_id.ok_or_else(ApiError::not_found_note)?;
|
||||
let workspace_slug = page
|
||||
.workspace_slug
|
||||
.as_deref()
|
||||
.ok_or_else(ApiError::not_found_note)?;
|
||||
let room_key = crate::state::AppState::note_room_key(workspace_slug, &page.resource_slug);
|
||||
let channel = state
|
||||
.note_channel(workspace_slug, &page.resource_slug)
|
||||
.await;
|
||||
let collaboration_snapshot = db::note_collaboration_snapshot(&state.db, note_id).await?;
|
||||
let collaborative_document = state
|
||||
.collaborative_document(
|
||||
&room_key,
|
||||
collaboration_snapshot.content,
|
||||
collaboration_snapshot.owner_map,
|
||||
collaboration_snapshot.revision_id,
|
||||
)
|
||||
.await;
|
||||
let mut document = collaborative_document.lock().await;
|
||||
let Some(next_content) =
|
||||
db::updated_public_task_content(&document.content, source_line, checked)
|
||||
else {
|
||||
return Ok(());
|
||||
};
|
||||
let base_revision_id = document.revision_id;
|
||||
let operation =
|
||||
collab::operation_from_edit(&document.content, &next_content, &document.owner_map);
|
||||
let (content, owner_map) = collab::apply_operation_to_document(
|
||||
&document.content,
|
||||
&document.owner_map,
|
||||
&operation,
|
||||
&[],
|
||||
)
|
||||
.map_err(|_| ApiError::bad_request("The task could not be updated"))?;
|
||||
let (revision_id, updated_at) = db::save_revision(
|
||||
&state.db,
|
||||
note_id,
|
||||
workspace_id,
|
||||
&content,
|
||||
Some("public"),
|
||||
&owner_map,
|
||||
)
|
||||
.await?;
|
||||
let update_id = u64::try_from(revision_id).unwrap_or_default().max(1);
|
||||
document.content.clone_from(&content);
|
||||
document.owner_map.clone_from(&owner_map);
|
||||
document.revision_id = revision_id;
|
||||
document.record(AppliedOperation {
|
||||
base_revision_id,
|
||||
revision_id,
|
||||
client_id: "public_task".into(),
|
||||
update_id,
|
||||
operation: operation.clone(),
|
||||
owner_replacements: Vec::new(),
|
||||
});
|
||||
let _ = channel.send(RoomEvent::Document(NoteUpdate {
|
||||
base_revision_id,
|
||||
revision_id,
|
||||
updated_at,
|
||||
author: Some("public".into()),
|
||||
client_id: "public_task".into(),
|
||||
update_id,
|
||||
operation,
|
||||
owner_replacements: Vec::new(),
|
||||
}));
|
||||
drop(document);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_public_task(
|
||||
State(state): State<SharedState>,
|
||||
headers: HeaderMap,
|
||||
@@ -480,7 +618,14 @@ pub async fn update_public_task(
|
||||
"Task updates are disabled for this page",
|
||||
));
|
||||
}
|
||||
let page = db::update_public_task(&state.db, &token, payload.source_line, payload.checked)
|
||||
if current.pad_id.is_some() {
|
||||
commit_public_pad_task_update(&state, ¤t, payload.source_line, payload.checked)
|
||||
.await?;
|
||||
} else {
|
||||
commit_public_note_task_update(&state, ¤t, payload.source_line, payload.checked)
|
||||
.await?;
|
||||
}
|
||||
let page = db::find_published_page(&state.db, &token)
|
||||
.await?
|
||||
.ok_or_else(ApiError::not_found_note)?;
|
||||
let files =
|
||||
@@ -564,19 +709,59 @@ pub async fn pad_restore(
|
||||
.fetch_optional(state.db.pool())
|
||||
.await?;
|
||||
let owner_map = owner_map.unwrap_or_else(|| "[]".into());
|
||||
let room_key = crate::state::AppState::pad_room_key(&slug);
|
||||
let channel = state.pad_channel(&slug).await;
|
||||
let collaboration_snapshot = db::pad_collaboration_snapshot(&state.db, pad.id).await?;
|
||||
let collaborative_document = state
|
||||
.collaborative_document(
|
||||
&room_key,
|
||||
collaboration_snapshot.content,
|
||||
collaboration_snapshot.owner_map,
|
||||
collaboration_snapshot.revision_id,
|
||||
)
|
||||
.await;
|
||||
let mut document = collaborative_document.lock().await;
|
||||
let base_revision_id = document.revision_id;
|
||||
let restored_owners = collab::owner_spans_from_map(&content, &owner_map);
|
||||
let operation = collab::replace_operation(
|
||||
document.content.encode_utf16().count(),
|
||||
content,
|
||||
restored_owners,
|
||||
);
|
||||
let (content, owner_map) = collab::apply_operation_to_document(
|
||||
&document.content,
|
||||
&document.owner_map,
|
||||
&operation,
|
||||
&[],
|
||||
)
|
||||
.map_err(|_| ApiError::bad_request("The selected revision could not be restored"))?;
|
||||
let (revision_id, updated_at) =
|
||||
db::save_pad_revision(&state.db, pad.id, &content, Some("restore"), &owner_map).await?;
|
||||
let update_id = u64::try_from(revision_id).unwrap_or_default().max(1);
|
||||
let applied = AppliedOperation {
|
||||
base_revision_id,
|
||||
revision_id,
|
||||
client_id: "server_restore".into(),
|
||||
update_id,
|
||||
operation: operation.clone(),
|
||||
owner_replacements: Vec::new(),
|
||||
};
|
||||
document.content.clone_from(&content);
|
||||
document.owner_map.clone_from(&owner_map);
|
||||
document.revision_id = revision_id;
|
||||
document.record(applied);
|
||||
let update = NoteUpdate {
|
||||
content,
|
||||
base_revision_id,
|
||||
revision_id,
|
||||
updated_at,
|
||||
author: Some("restore".into()),
|
||||
owner_map,
|
||||
client_id: "server_restore".into(),
|
||||
update_id,
|
||||
operation,
|
||||
owner_replacements: Vec::new(),
|
||||
};
|
||||
let _ = state
|
||||
.pad_channel(&slug)
|
||||
.await
|
||||
.send(RoomEvent::Document(update));
|
||||
let _ = channel.send(RoomEvent::Document(update));
|
||||
drop(document);
|
||||
Ok(Json(serde_json::json!({"ok": true})))
|
||||
}
|
||||
|
||||
@@ -591,7 +776,8 @@ pub(super) async fn authorized_pad(
|
||||
let pad = db::find_pad(&state.db, slug)
|
||||
.await?
|
||||
.ok_or_else(ApiError::not_found_note)?;
|
||||
let token_level = request_access_level(state, headers, "pad", slug, access_token, bearer).await?;
|
||||
let token_level =
|
||||
request_access_level(state, headers, "pad", slug, access_token, bearer).await?;
|
||||
if pad.is_private != 0 && token_level == AccessLevel::None {
|
||||
return Err(ApiError::not_found_note());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user