Detailed changes
@@ -140,6 +140,14 @@ impl ChannelRole {
Guest | Banned => false,
}
}
+
+ pub fn can_edit_projects(&self) -> bool {
+ use ChannelRole::*;
+ match self {
+ Admin | Member => true,
+ Guest | Banned => false,
+ }
+ }
}
impl From<proto::ChannelRole> for ChannelRole {
@@ -777,6 +777,44 @@ impl Database {
.await
}
+ pub async fn host_for_mutating_project_request(
+ &self,
+ project_id: ProjectId,
+ connection_id: ConnectionId,
+ ) -> Result<ConnectionId> {
+ let room_id = self.room_id_for_project(project_id).await?;
+ self.room_transaction(room_id, |tx| async move {
+ let current_participant = room_participant::Entity::find()
+ .filter(room_participant::Column::RoomId.eq(room_id))
+ .filter(room_participant::Column::AnsweringConnectionId.eq(connection_id.id))
+ .one(&*tx)
+ .await?
+ .ok_or_else(|| anyhow!("no such room"))?;
+
+ if !current_participant
+ .role
+ .unwrap_or(ChannelRole::Guest)
+ .can_edit_projects()
+ {
+ Err(anyhow!("not authorized to edit projects"))?;
+ }
+
+ let host = project_collaborator::Entity::find()
+ .filter(
+ project_collaborator::Column::ProjectId
+ .eq(project_id)
+ .and(project_collaborator::Column::IsHost.eq(true)),
+ )
+ .one(&*tx)
+ .await?
+ .ok_or_else(|| anyhow!("failed to read project host"))?;
+
+ Ok(host.connection())
+ })
+ .await
+ .map(|guard| guard.into_inner())
+ }
+
pub async fn project_collaborators(
&self,
project_id: ProjectId,
@@ -217,39 +217,43 @@ impl Server {
.add_message_handler(update_diagnostic_summary)
.add_message_handler(update_worktree_settings)
.add_message_handler(refresh_inlay_hints)
- .add_request_handler(forward_project_request::<proto::GetHover>)
- .add_request_handler(forward_project_request::<proto::GetDefinition>)
- .add_request_handler(forward_project_request::<proto::GetTypeDefinition>)
- .add_request_handler(forward_project_request::<proto::GetReferences>)
- .add_request_handler(forward_project_request::<proto::SearchProject>)
- .add_request_handler(forward_project_request::<proto::GetDocumentHighlights>)
- .add_request_handler(forward_project_request::<proto::GetProjectSymbols>)
- .add_request_handler(forward_project_request::<proto::OpenBufferForSymbol>)
- .add_request_handler(forward_project_request::<proto::OpenBufferById>)
- .add_request_handler(forward_project_request::<proto::OpenBufferByPath>)
- .add_request_handler(forward_project_request::<proto::GetCompletions>)
- .add_request_handler(forward_project_request::<proto::ApplyCompletionAdditionalEdits>)
- .add_request_handler(forward_project_request::<proto::ResolveCompletionDocumentation>)
- .add_request_handler(forward_project_request::<proto::GetCodeActions>)
- .add_request_handler(forward_project_request::<proto::ApplyCodeAction>)
- .add_request_handler(forward_project_request::<proto::PrepareRename>)
- .add_request_handler(forward_project_request::<proto::PerformRename>)
- .add_request_handler(forward_project_request::<proto::ReloadBuffers>)
- .add_request_handler(forward_project_request::<proto::SynchronizeBuffers>)
- .add_request_handler(forward_project_request::<proto::FormatBuffers>)
- .add_request_handler(forward_project_request::<proto::CreateProjectEntry>)
- .add_request_handler(forward_project_request::<proto::RenameProjectEntry>)
- .add_request_handler(forward_project_request::<proto::CopyProjectEntry>)
- .add_request_handler(forward_project_request::<proto::DeleteProjectEntry>)
- .add_request_handler(forward_project_request::<proto::ExpandProjectEntry>)
- .add_request_handler(forward_project_request::<proto::OnTypeFormatting>)
- .add_request_handler(forward_project_request::<proto::InlayHints>)
+ .add_request_handler(forward_read_only_project_request::<proto::GetHover>)
+ .add_request_handler(forward_read_only_project_request::<proto::GetDefinition>)
+ .add_request_handler(forward_read_only_project_request::<proto::GetTypeDefinition>)
+ .add_request_handler(forward_read_only_project_request::<proto::GetReferences>)
+ .add_request_handler(forward_read_only_project_request::<proto::SearchProject>)
+ .add_request_handler(forward_read_only_project_request::<proto::GetDocumentHighlights>)
+ .add_request_handler(forward_read_only_project_request::<proto::GetProjectSymbols>)
+ .add_request_handler(forward_read_only_project_request::<proto::OpenBufferForSymbol>)
+ .add_request_handler(forward_read_only_project_request::<proto::OpenBufferById>)
+ .add_request_handler(forward_read_only_project_request::<proto::SynchronizeBuffers>)
+ .add_request_handler(forward_read_only_project_request::<proto::InlayHints>)
+ .add_request_handler(forward_mutating_project_request::<proto::OpenBufferByPath>)
+ .add_request_handler(forward_mutating_project_request::<proto::GetCompletions>)
+ .add_request_handler(
+ forward_mutating_project_request::<proto::ApplyCompletionAdditionalEdits>,
+ )
+ .add_request_handler(
+ forward_mutating_project_request::<proto::ResolveCompletionDocumentation>,
+ )
+ .add_request_handler(forward_mutating_project_request::<proto::GetCodeActions>)
+ .add_request_handler(forward_mutating_project_request::<proto::ApplyCodeAction>)
+ .add_request_handler(forward_mutating_project_request::<proto::PrepareRename>)
+ .add_request_handler(forward_mutating_project_request::<proto::PerformRename>)
+ .add_request_handler(forward_mutating_project_request::<proto::ReloadBuffers>)
+ .add_request_handler(forward_mutating_project_request::<proto::FormatBuffers>)
+ .add_request_handler(forward_mutating_project_request::<proto::CreateProjectEntry>)
+ .add_request_handler(forward_mutating_project_request::<proto::RenameProjectEntry>)
+ .add_request_handler(forward_mutating_project_request::<proto::CopyProjectEntry>)
+ .add_request_handler(forward_mutating_project_request::<proto::DeleteProjectEntry>)
+ .add_request_handler(forward_mutating_project_request::<proto::ExpandProjectEntry>)
+ .add_request_handler(forward_mutating_project_request::<proto::OnTypeFormatting>)
+ .add_request_handler(forward_mutating_project_request::<proto::SaveBuffer>)
.add_message_handler(create_buffer_for_peer)
.add_request_handler(update_buffer)
.add_message_handler(update_buffer_file)
.add_message_handler(buffer_reloaded)
.add_message_handler(buffer_saved)
- .add_request_handler(forward_project_request::<proto::SaveBuffer>)
.add_request_handler(get_users)
.add_request_handler(fuzzy_search_users)
.add_request_handler(request_contact)
@@ -1741,7 +1745,7 @@ async fn update_language_server(
Ok(())
}
-async fn forward_project_request<T>(
+async fn forward_read_only_project_request<T>(
request: T,
response: Response<T>,
session: Session,
@@ -1772,6 +1776,30 @@ where
Ok(())
}
+async fn forward_mutating_project_request<T>(
+ request: T,
+ response: Response<T>,
+ session: Session,
+) -> Result<()>
+where
+ T: EntityMessage + RequestMessage,
+{
+ let project_id = ProjectId::from_proto(request.remote_entity_id());
+ let host_connection_id = session
+ .db()
+ .await
+ .host_for_mutating_project_request(project_id, session.connection_id)
+ .await?;
+
+ let payload = session
+ .peer
+ .forward_request(session.connection_id, host_connection_id, request)
+ .await?;
+
+ response.send(payload)?;
+ Ok(())
+}
+
async fn create_buffer_for_peer(
request: proto::CreateBufferForPeer,
session: Session,
@@ -82,5 +82,13 @@ async fn test_channel_guests(
project_b.read_with(cx_b, |project, _| project.remote_id()),
Some(project_id),
);
- assert!(project_b.read_with(cx_b, |project, _| project.is_read_only()))
+ assert!(project_b.read_with(cx_b, |project, _| project.is_read_only()));
+
+ assert!(project_b
+ .update(cx_b, |project, cx| {
+ let worktree_id = project.worktrees().next().unwrap().read(cx).id();
+ project.create_entry((worktree_id, "b.txt"), false, cx)
+ })
+ .await
+ .is_err())
}