Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions application/src/dto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ pub mod activitypub;
pub mod block_mute;
pub mod media;
pub mod metadata;
pub mod organization;
pub mod pagination;
pub mod profile;
29 changes: 29 additions & 0 deletions application/src/dto/organization.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use kernel::prelude::entity::{OrgRole, OrganizationMembershipStatus};
use time::OffsetDateTime;

#[derive(Debug)]
pub struct CreateOrganizationDto {
pub name: String,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct OrganizationSummaryDto {
pub account_id: String,
pub name: String,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MyOrganizationDto {
pub organization: OrganizationSummaryDto,
pub role: OrgRole,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct OrganizationMemberDto {
pub account_id: String,
pub name: String,
pub role: OrgRole,
pub status: OrganizationMembershipStatus,
pub invited_by: String,
pub created_at: OffsetDateTime,
}
38 changes: 21 additions & 17 deletions application/src/projection/account_projector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ use kernel::interfaces::read_model::{
DependOnProfileReadModel, MetadataReadModel, ProfileReadModel,
};
use kernel::interfaces::repository::{DependOnFollowRepository, FollowRepository};
use kernel::prelude::entity::{Account, AccountEvent, AccountId, EventEnvelope, FollowTargetId};
use kernel::prelude::entity::{
Account, AccountEvent, AccountId, AccountKind, EventEnvelope, FollowTargetId,
};
use kernel::KernelError;
use std::collections::HashMap;
use std::future::Future;
Expand Down Expand Up @@ -192,22 +194,24 @@ pub trait ProjectAccountBatch:
self.account_read_model()
.link_auth_account(executor, account_id, &auth_id)
.await?;
if let Err(e) = self
.permission_writer()
.create_relation(
&RelationTarget::Account {
account_id: account_id.clone(),
relation: AccountRelation::Owner,
},
&auth_id,
)
.await
{
tracing::warn!(
"Account projector: failed to create Owner relation for account {:?}: {:?}",
account_id,
e
);
if account.kind() == &AccountKind::Personal {
if let Err(e) = self
.permission_writer()
.create_relation(
&RelationTarget::Account {
account_id: account_id.clone(),
relation: AccountRelation::Owner,
},
&auth_id,
)
.await
{
tracing::warn!(
"Account projector: failed to create Owner relation for account {:?}: {:?}",
account_id,
e
);
}
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions application/src/projection/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ async fn older_version_upsert_is_a_noop() {
AccountEvent::Created {
name: AccountName::new(kernel::test_utils::unique_account_name()),
is_bot: AccountIsBot::new(false),
kind: kernel::prelude::entity::AccountKind::Personal,
nanoid: Nanoid::default(),
auth_account_id: AuthAccountId::default(),
},
Expand All @@ -297,6 +298,7 @@ async fn older_version_upsert_is_a_noop() {
AccountEvent::Created {
name: AccountName::new(kernel::test_utils::unique_account_name()),
is_bot: AccountIsBot::new(false),
kind: kernel::prelude::entity::AccountKind::Personal,
nanoid: Nanoid::default(),
auth_account_id: AuthAccountId::default(),
},
Expand Down
1 change: 1 addition & 0 deletions application/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod auth_account;
pub mod block;
pub mod media;
pub mod mute;
pub mod organization;
pub mod report;
pub mod session_context;

Expand Down
193 changes: 191 additions & 2 deletions application/src/service/account/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::permission::{account_view, check_permission};
use kernel::interfaces::database::DatabaseConnection;
use kernel::interfaces::permission::DependOnPermissionChecker;
use kernel::interfaces::read_model::{AccountQuery, DependOnAccountQuery};
use kernel::prelude::entity::{Account, AuthAccountId, Nanoid};
use kernel::prelude::entity::{Account, AccountKind, AuthAccountId, Nanoid};
use kernel::KernelError;
use std::future::Future;

Expand All @@ -28,7 +28,10 @@ pub trait GetAccountUseCase:
let accounts = self
.account_query()
.find_by_auth_id(&mut conn, auth_account_id)
.await?;
.await?
.into_iter()
.filter(|account| account.kind() == &AccountKind::Personal)
.collect();
let cursor = if let Some(cursor) = cursor {
let id: Nanoid<Account> = Nanoid::new(cursor);
self.account_query().find_by_nanoid(&mut conn, &id).await?
Expand Down Expand Up @@ -71,3 +74,189 @@ pub trait GetAccountUseCase:
}

impl<T> GetAccountUseCase for T where T: 'static + DependOnAccountQuery + DependOnPermissionChecker {}

#[cfg(test)]
mod tests {
use super::*;
use kernel::interfaces::database::{Connection, DependOnDatabaseConnection};
use kernel::interfaces::permission::{InstanceRole, PermissionChecker, PermissionReq};
use kernel::prelude::entity::{AccountId, AccountName};
use kernel::test_utils::AccountBuilder;

struct MockConnection;
impl Connection for MockConnection {}

struct MockDatabase;
impl kernel::interfaces::database::DatabaseConnection for MockDatabase {
type Connection = MockConnection;
async fn connection(&self) -> error_stack::Result<MockConnection, KernelError> {
Ok(MockConnection)
}
}

struct MockAccounts(Vec<Account>);
impl AccountQuery for MockAccounts {
type Connection = MockConnection;
async fn find_by_id(
&self,
_: &mut MockConnection,
id: &AccountId,
) -> error_stack::Result<Option<Account>, KernelError> {
Ok(self.0.iter().find(|account| account.id() == id).cloned())
}
async fn find_by_auth_id(
&self,
_: &mut MockConnection,
_: &AuthAccountId,
) -> error_stack::Result<Vec<Account>, KernelError> {
Ok(self.0.clone())
}
async fn find_auth_account_id_by_account_id(
&self,
_: &mut MockConnection,
_: &AccountId,
) -> error_stack::Result<Option<AuthAccountId>, KernelError> {
Ok(None)
}
async fn find_by_name(
&self,
_: &mut MockConnection,
name: &AccountName,
) -> error_stack::Result<Option<Account>, KernelError> {
Ok(self
.0
.iter()
.find(|account| account.name() == name)
.cloned())
}
async fn find_by_nanoid(
&self,
_: &mut MockConnection,
nanoid: &Nanoid<Account>,
) -> error_stack::Result<Option<Account>, KernelError> {
Ok(self
.0
.iter()
.find(|account| account.nanoid() == nanoid)
.cloned())
}
async fn find_by_nanoids(
&self,
_: &mut MockConnection,
nanoids: &[Nanoid<Account>],
) -> error_stack::Result<Vec<Account>, KernelError> {
Ok(self
.0
.iter()
.filter(|account| nanoids.contains(account.nanoid()))
.cloned()
.collect())
}
async fn find_by_id_unfiltered(
&self,
executor: &mut MockConnection,
id: &AccountId,
) -> error_stack::Result<Option<Account>, KernelError> {
self.find_by_id(executor, id).await
}
async fn find_by_nanoid_unfiltered(
&self,
executor: &mut MockConnection,
nanoid: &Nanoid<Account>,
) -> error_stack::Result<Option<Account>, KernelError> {
self.find_by_nanoid(executor, nanoid).await
}
async fn find_by_nanoids_unfiltered(
&self,
executor: &mut MockConnection,
nanoids: &[Nanoid<Account>],
) -> error_stack::Result<Vec<Account>, KernelError> {
self.find_by_nanoids(executor, nanoids).await
}
async fn find_by_nanoid_including_deleted(
&self,
executor: &mut MockConnection,
nanoid: &Nanoid<Account>,
) -> error_stack::Result<Option<Account>, KernelError> {
self.find_by_nanoid(executor, nanoid).await
}
async fn is_linked_including_deleted(
&self,
_: &mut MockConnection,
_: &AuthAccountId,
_: &AccountId,
) -> error_stack::Result<bool, KernelError> {
Ok(false)
}
}

struct AllowPermissions;
impl PermissionChecker for AllowPermissions {
async fn check(
&self,
_: &AuthAccountId,
_: &PermissionReq,
) -> error_stack::Result<bool, KernelError> {
Ok(true)
}
async fn list_instance_roles(
&self,
_: &AuthAccountId,
) -> error_stack::Result<Vec<InstanceRole>, KernelError> {
Ok(Vec::new())
}
}

struct Module {
database: MockDatabase,
accounts: MockAccounts,
permissions: AllowPermissions,
}
impl DependOnDatabaseConnection for Module {
type DatabaseConnection = MockDatabase;
fn database_connection(&self) -> &MockDatabase {
&self.database
}
}
impl DependOnAccountQuery for Module {
type AccountQuery = MockAccounts;
fn account_query(&self) -> &MockAccounts {
&self.accounts
}
}
impl DependOnPermissionChecker for Module {
type PermissionChecker = AllowPermissions;
fn permission_checker(&self) -> &AllowPermissions {
&self.permissions
}
}

#[tokio::test]
async fn get_all_accounts_excludes_organization_accounts() {
kernel::ensure_generator_initialized();
let personal = AccountBuilder::new()
.nanoid(Nanoid::new("personal"))
.build();
let organization = AccountBuilder::new()
.kind(AccountKind::Organization)
.nanoid(Nanoid::new("organization"))
.build();
let module = Module {
database: MockDatabase,
accounts: MockAccounts(vec![personal, organization]),
permissions: AllowPermissions,
};

let result = module
.get_all_accounts(
&AuthAccountId::default(),
Pagination::new(None, None, Default::default()),
)
.await
.unwrap()
.unwrap();

assert_eq!(result.len(), 1);
assert_eq!(result[0].nanoid, "personal");
}
}
1 change: 1 addition & 0 deletions application/src/service/characterization_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,7 @@ delegate_database_dependence! {
kernel::interfaces::repository::DependOnImageRepository { ImageRepository, image_repository },
kernel::interfaces::repository::DependOnMetadataRepository { MetadataRepository, metadata_repository },
kernel::interfaces::repository::DependOnMuteRepository { MuteRepository, mute_repository },
kernel::interfaces::repository::DependOnOrganizationMembershipRepository { OrganizationMembershipRepository, organization_membership_repository },
kernel::interfaces::repository::DependOnOutboxActivityRepository { OutboxActivityRepository, outbox_activity_repository },
kernel::interfaces::repository::DependOnProfileRepository { ProfileRepository, profile_repository },
kernel::interfaces::repository::DependOnRemoteAccountRepository { RemoteAccountRepository, remote_account_repository },
Expand Down
10 changes: 10 additions & 0 deletions application/src/service/organization.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
mod create;
mod list;
mod membership;

pub use create::*;
pub use list::*;
pub use membership::*;

#[cfg(test)]
mod tests;
Loading
Loading