Make project id optional when following - server only

This commit is contained in:
Max Brunsfeld 2023-09-19 15:37:33 -07:00
parent 83455028b0
commit c71566e7f5
10 changed files with 204 additions and 55 deletions

View file

@ -738,7 +738,7 @@ impl Database {
Condition::any()
.add(
Condition::all()
.add(follower::Column::ProjectId.eq(project_id))
.add(follower::Column::ProjectId.eq(Some(project_id)))
.add(
follower::Column::LeaderConnectionServerId
.eq(connection.owner_id),
@ -747,7 +747,7 @@ impl Database {
)
.add(
Condition::all()
.add(follower::Column::ProjectId.eq(project_id))
.add(follower::Column::ProjectId.eq(Some(project_id)))
.add(
follower::Column::FollowerConnectionServerId
.eq(connection.owner_id),
@ -862,13 +862,95 @@ impl Database {
.await
}
pub async fn check_can_follow(
&self,
room_id: RoomId,
project_id: Option<ProjectId>,
leader_id: ConnectionId,
follower_id: ConnectionId,
) -> Result<()> {
let mut found_leader = false;
let mut found_follower = false;
self.transaction(|tx| async move {
if let Some(project_id) = project_id {
let mut rows = project_collaborator::Entity::find()
.filter(project_collaborator::Column::ProjectId.eq(project_id))
.stream(&*tx)
.await?;
while let Some(row) = rows.next().await {
let row = row?;
let connection = row.connection();
if connection == leader_id {
found_leader = true;
} else if connection == follower_id {
found_follower = true;
}
}
} else {
let mut rows = room_participant::Entity::find()
.filter(room_participant::Column::RoomId.eq(room_id))
.stream(&*tx)
.await?;
while let Some(row) = rows.next().await {
let row = row?;
if let Some(connection) = row.answering_connection() {
if connection == leader_id {
found_leader = true;
} else if connection == follower_id {
found_follower = true;
}
}
}
}
if !found_leader || !found_follower {
Err(anyhow!("not a room participant"))?;
}
Ok(())
})
.await
}
pub async fn check_can_unfollow(
&self,
room_id: RoomId,
project_id: Option<ProjectId>,
leader_id: ConnectionId,
follower_id: ConnectionId,
) -> Result<()> {
self.transaction(|tx| async move {
follower::Entity::find()
.filter(
Condition::all()
.add(follower::Column::RoomId.eq(room_id))
.add(follower::Column::ProjectId.eq(project_id))
.add(follower::Column::LeaderConnectionId.eq(leader_id.id as i32))
.add(follower::Column::FollowerConnectionId.eq(follower_id.id as i32))
.add(
follower::Column::LeaderConnectionServerId
.eq(leader_id.owner_id as i32),
)
.add(
follower::Column::FollowerConnectionServerId
.eq(follower_id.owner_id as i32),
),
)
.one(&*tx)
.await?
.ok_or_else(|| anyhow!("not a follower"))?;
Ok(())
})
.await
}
pub async fn follow(
&self,
project_id: ProjectId,
room_id: RoomId,
project_id: Option<ProjectId>,
leader_connection: ConnectionId,
follower_connection: ConnectionId,
) -> Result<RoomGuard<proto::Room>> {
let room_id = self.room_id_for_project(project_id).await?;
self.room_transaction(room_id, |tx| async move {
follower::ActiveModel {
room_id: ActiveValue::set(room_id),
@ -894,15 +976,16 @@ impl Database {
pub async fn unfollow(
&self,
project_id: ProjectId,
room_id: RoomId,
project_id: Option<ProjectId>,
leader_connection: ConnectionId,
follower_connection: ConnectionId,
) -> Result<RoomGuard<proto::Room>> {
let room_id = self.room_id_for_project(project_id).await?;
self.room_transaction(room_id, |tx| async move {
follower::Entity::delete_many()
.filter(
Condition::all()
.add(follower::Column::RoomId.eq(room_id))
.add(follower::Column::ProjectId.eq(project_id))
.add(
follower::Column::LeaderConnectionServerId

View file

@ -960,6 +960,65 @@ impl Database {
Ok(room)
}
pub async fn room_id_for_connection(&self, connection_id: ConnectionId) -> Result<RoomId> {
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
enum QueryRoomId {
RoomId,
}
self.transaction(|tx| async move {
Ok(room_participant::Entity::find()
.select_only()
.column(room_participant::Column::RoomId)
.filter(
Condition::all()
.add(room_participant::Column::AnsweringConnectionId.eq(connection_id.id))
.add(
room_participant::Column::AnsweringConnectionServerId
.eq(ServerId(connection_id.owner_id as i32)),
),
)
.into_values::<_, QueryRoomId>()
.one(&*tx)
.await?
.ok_or_else(|| anyhow!("no room for connection {:?}", connection_id))?)
})
.await
}
pub async fn room_connection_ids(
&self,
room_id: RoomId,
connection_id: ConnectionId,
) -> Result<RoomGuard<HashSet<ConnectionId>>> {
self.room_transaction(room_id, |tx| async move {
let mut participants = room_participant::Entity::find()
.filter(room_participant::Column::RoomId.eq(room_id))
.stream(&*tx)
.await?;
let mut is_participant = false;
let mut connection_ids = HashSet::default();
while let Some(participant) = participants.next().await {
let participant = participant?;
if let Some(answering_connection) = participant.answering_connection() {
if answering_connection == connection_id {
is_participant = true;
} else {
connection_ids.insert(answering_connection);
}
}
}
if !is_participant {
Err(anyhow!("not a room participant"))?;
}
Ok(connection_ids)
})
.await
}
async fn get_channel_room(
&self,
room_id: RoomId,
@ -1064,7 +1123,7 @@ impl Database {
followers.push(proto::Follower {
leader_id: Some(db_follower.leader_connection().into()),
follower_id: Some(db_follower.follower_connection().into()),
project_id: db_follower.project_id.to_proto(),
project_id: db_follower.project_id.map(|id| id.to_proto()),
});
}