| @@ -37,8 +37,9 @@ impl Database { · 36 unmodified lines |
| 37 | 37 | } |
| 38 | 38 | |
| 39 | 39 | let channel = channel::ActiveModel { |
| 40 | + id: ActiveValue::NotSet, |
| 40 | 41 | name: ActiveValue::Set(name.to_string()), |
| 41 | | − ..Default::default() |
| 42 | + visibility: ActiveValue::Set(ChannelVisibility::ChannelMembers), |
| 42 | 43 | } |
| 43 | 44 | .insert(&*tx) |
| 44 | 45 | .await?; |
| @@ -89,6 +90,29 @@ impl Database { · 44 unmodified lines |
| 89 | 90 | .await |
| 90 | 91 | } |
| 91 | 92 | |
| 93 | + pub async fn set_channel_visibility( |
| 94 | + &self, |
| 95 | + channel_id: ChannelId, |
| 96 | + visibility: ChannelVisibility, |
| 97 | + user_id: UserId, |
| 98 | + ) -> Result<()> { |
| 99 | + self.transaction(move |tx| async move { |
| 100 | + self.check_user_is_channel_admin(channel_id, user_id, &*tx) |
| 101 | + .await?; |
| 102 | + |
| 103 | + channel::ActiveModel { |
| 104 | + id: ActiveValue::Unchanged(channel_id), |
| 105 | + visibility: ActiveValue::Set(visibility), |
| 106 | + ..Default::default() |
| 107 | + } |
| 108 | + .update(&*tx) |
| 109 | + .await?; |
| 110 | + |
| 111 | + Ok(()) |
| 112 | + }) |
| 113 | + .await |
| 114 | + } |
| 115 | + |
| 92 | 116 | pub async fn delete_channel( |
| 93 | 117 | &self, |
| 94 | 118 | channel_id: ChannelId, |
| @@ -160,11 +184,11 @@ impl Database { · 65 unmodified lines |
| 160 | 184 | &self, |
| 161 | 185 | channel_id: ChannelId, |
| 162 | 186 | invitee_id: UserId, |
| 163 | | − inviter_id: UserId, |
| 187 | + admin_id: UserId, |
| 164 | 188 | role: ChannelRole, |
| 165 | 189 | ) -> Result<()> { |
| 166 | 190 | self.transaction(move |tx| async move { |
| 167 | | − self.check_user_is_channel_admin(channel_id, inviter_id, &*tx) |
| 191 | + self.check_user_is_channel_admin(channel_id, admin_id, &*tx) |
| 168 | 192 | .await?; |
| 169 | 193 | |
| 170 | 194 | channel_member::ActiveModel { |
| @@ -262,10 +286,10 @@ impl Database { · 91 unmodified lines |
| 262 | 286 | &self, |
| 263 | 287 | channel_id: ChannelId, |
| 264 | 288 | member_id: UserId, |
| 265 | | − remover_id: UserId, |
| 289 | + admin_id: UserId, |
| 266 | 290 | ) -> Result<()> { |
| 267 | 291 | self.transaction(|tx| async move { |
| 268 | | − self.check_user_is_channel_admin(channel_id, remover_id, &*tx) |
| 292 | + self.check_user_is_channel_admin(channel_id, admin_id, &*tx) |
| 269 | 293 | .await?; |
| 270 | 294 | |
| 271 | 295 | let result = channel_member::Entity::delete_many() |
| @@ -481,12 +505,12 @@ impl Database { · 209 unmodified lines |
| 481 | 505 | pub async fn set_channel_member_role( |
| 482 | 506 | &self, |
| 483 | 507 | channel_id: ChannelId, |
| 484 | | − from: UserId, |
| 508 | + admin_id: UserId, |
| 485 | 509 | for_user: UserId, |
| 486 | 510 | role: ChannelRole, |
| 487 | 511 | ) -> Result<()> { |
| 488 | 512 | self.transaction(|tx| async move { |
| 489 | | − self.check_user_is_channel_admin(channel_id, from, &*tx) |
| 513 | + self.check_user_is_channel_admin(channel_id, admin_id, &*tx) |
| 490 | 514 | .await?; |
| 491 | 515 | |
| 492 | 516 | let result = channel_member::Entity::update_many() |
| @@ -613,43 +637,147 @@ impl Database { · 120 unmodified lines |
| 613 | 637 | Ok(user_ids) |
| 614 | 638 | } |
| 615 | 639 | |
| 640 | + pub async fn check_user_is_channel_admin( |
| 641 | + &self, |
| 642 | + channel_id: ChannelId, |
| 643 | + user_id: UserId, |
| 644 | + tx: &DatabaseTransaction, |
| 645 | + ) -> Result<()> { |
| 646 | + match self.channel_role_for_user(channel_id, user_id, tx).await? { |
| 647 | + Some(ChannelRole::Admin) => Ok(()), |
| 648 | + Some(ChannelRole::Member) |
| 649 | + | Some(ChannelRole::Banned) |
| 650 | + | Some(ChannelRole::Guest) |
| 651 | + | None => Err(anyhow!( |
| 652 | + "user is not a channel admin or channel does not exist" |
| 653 | + ))?, |
| 654 | + } |
| 655 | + } |
| 656 | + |
| 616 | 657 | pub async fn check_user_is_channel_member( |
| 617 | 658 | &self, |
| 618 | 659 | channel_id: ChannelId, |
| 619 | 660 | user_id: UserId, |
| 620 | 661 | tx: &DatabaseTransaction, |
| 621 | 662 | ) -> Result<()> { |
| 622 | | − let channel_ids = self.get_channel_ancestors(channel_id, tx).await?; |
| 623 | | − channel_member::Entity::find() |
| 624 | | − .filter( |
| 625 | | − channel_member::Column::ChannelId |
| 626 | | − .is_in(channel_ids) |
| 627 | | − .and(channel_member::Column::UserId.eq(user_id)), |
| 628 | | − ) |
| 629 | | − .one(&*tx) |
| 630 | | − .await? |
| 631 | | − .ok_or_else(|| anyhow!("user is not a channel member or channel does not exist"))?; |
| 632 | | − Ok(()) |
| 663 | + match self.channel_role_for_user(channel_id, user_id, tx).await? { |
| 664 | + Some(ChannelRole::Admin) | Some(ChannelRole::Member) => Ok(()), |
| 665 | + Some(ChannelRole::Banned) | Some(ChannelRole::Guest) | None => Err(anyhow!( |
| 666 | + "user is not a channel member or channel does not exist" |
| 667 | + ))?, |
| 668 | + } |
| 633 | 669 | } |
| 634 | 670 | |
| 635 | | − pub async fn check_user_is_channel_admin( |
| 671 | + pub async fn check_user_is_channel_participant( |
| 636 | 672 | &self, |
| 637 | 673 | channel_id: ChannelId, |
| 638 | 674 | user_id: UserId, |
| 639 | 675 | tx: &DatabaseTransaction, |
| 640 | 676 | ) -> Result<()> { |
| 677 | + match self.channel_role_for_user(channel_id, user_id, tx).await? { |
| 678 | + Some(ChannelRole::Admin) | Some(ChannelRole::Member) | Some(ChannelRole::Guest) => { |
| 679 | + Ok(()) |
| 680 | + } |
| 681 | + Some(ChannelRole::Banned) | None => Err(anyhow!( |
| 682 | + "user is not a channel participant or channel does not exist" |
| 683 | + ))?, |
| 684 | + } |
| 685 | + } |
| 686 | + |
| 687 | + pub async fn channel_role_for_user( |
| 688 | + &self, |
| 689 | + channel_id: ChannelId, |
| 690 | + user_id: UserId, |
| 691 | + tx: &DatabaseTransaction, |
| 692 | + ) -> Result<Option<ChannelRole>> { |
| 641 | 693 | let channel_ids = self.get_channel_ancestors(channel_id, tx).await?; |
| 642 | | − channel_member::Entity::find() |
| 694 | + |
| 695 | + #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] |
| 696 | + enum QueryChannelMembership { |
| 697 | + ChannelId, |
| 698 | + Role, |
| 699 | + Admin, |
| 700 | + Visibility, |
| 701 | + } |
| 702 | + |
| 703 | + let mut rows = channel_member::Entity::find() |
| 704 | + .left_join(channel::Entity) |
| 643 | 705 | .filter( |
| 644 | 706 | channel_member::Column::ChannelId |
| 645 | 707 | .is_in(channel_ids) |
| 646 | | − .and(channel_member::Column::UserId.eq(user_id)) |
| 647 | | − .and(channel_member::Column::Admin.eq(true)), |
| 708 | + .and(channel_member::Column::UserId.eq(user_id)), |
| 648 | 709 | ) |
| 649 | | − .one(&*tx) |
| 650 | | − .await? |
| 651 | | − .ok_or_else(|| anyhow!("user is not a channel admin or channel does not exist"))?; |
| 652 | | − Ok(()) |
| 710 | + .select_only() |
| 711 | + .column(channel_member::Column::ChannelId) |
| 712 | + .column(channel_member::Column::Role) |
| 713 | + .column(channel_member::Column::Admin) |
| 714 | + .column(channel::Column::Visibility) |
| 715 | + .into_values::<_, QueryChannelMembership>() |
| 716 | + .stream(&*tx) |
| 717 | + .await?; |
| 718 | + |
| 719 | + let mut is_admin = false; |
| 720 | + let mut is_member = false; |
| 721 | + let mut is_participant = false; |
| 722 | + let mut is_banned = false; |
| 723 | + let mut current_channel_visibility = None; |
| 724 | + |
| 725 | + // note these channels are not iterated in any particular order, |
| 726 | + // our current logic takes the highest permission available. |
| 727 | + while let Some(row) = rows.next().await { |
| 728 | + let (ch_id, role, admin, visibility): ( |
| 729 | + ChannelId, |
| 730 | + Option<ChannelRole>, |
| 731 | + bool, |
| 732 | + ChannelVisibility, |
| 733 | + ) = row?; |
| 734 | + match role { |
| 735 | + Some(ChannelRole::Admin) => is_admin = true, |
| 736 | + Some(ChannelRole::Member) => is_member = true, |
| 737 | + Some(ChannelRole::Guest) => { |
| 738 | + if visibility == ChannelVisibility::Public { |
| 739 | + is_participant = true |
| 740 | + } |
| 741 | + } |
| 742 | + Some(ChannelRole::Banned) => is_banned = true, |
| 743 | + None => { |
| 744 | + // rows created from pre-role collab server. |
| 745 | + if admin { |
| 746 | + is_admin = true |
| 747 | + } else { |
| 748 | + is_member = true |
| 749 | + } |
| 750 | + } |
| 751 | + } |
| 752 | + if channel_id == ch_id { |
| 753 | + current_channel_visibility = Some(visibility); |
| 754 | + } |
| 755 | + } |
| 756 | + // free up database connection |
| 757 | + drop(rows); |
| 758 | + |
| 759 | + Ok(if is_admin { |
| 760 | + Some(ChannelRole::Admin) |
| 761 | + } else if is_member { |
| 762 | + Some(ChannelRole::Member) |
| 763 | + } else if is_banned { |
| 764 | + Some(ChannelRole::Banned) |
| 765 | + } else if is_participant { |
| 766 | + if current_channel_visibility.is_none() { |
| 767 | + current_channel_visibility = channel::Entity::find() |
| 768 | + .filter(channel::Column::Id.eq(channel_id)) |
| 769 | + .one(&*tx) |
| 770 | + .await? |
| 771 | + .map(|channel| channel.visibility); |
| 772 | + } |
| 773 | + if current_channel_visibility == Some(ChannelVisibility::Public) { |
| 774 | + Some(ChannelRole::Guest) |
| 775 | + } else { |
| 776 | + None |
| 777 | + } |
| 778 | + } else { |
| 779 | + None |
| 780 | + }) |
| 653 | 781 | } |
| 654 | 782 | |
| 655 | 783 | /// Returns the channel ancestors, deepest first |