-
Notifications
You must be signed in to change notification settings - Fork 43
Expand file tree
/
Copy pathlist_organization.py
More file actions
133 lines (119 loc) · 4.38 KB
/
Copy pathlist_organization.py
File metadata and controls
133 lines (119 loc) · 4.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS
from __future__ import annotations
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager
import click
import pydantic
from parsec._parsec import (
ActiveUsersLimit,
DateTime,
EmailAddress,
OrganizationID,
ParsecAddr,
SecretKey,
)
from parsec.cli.options import asyncio_run, db_server_options, logging_config_options
from parsec.components.memory.datamodel import MemoryDatamodel
from parsec.components.memory.events import event_bus_factory
from parsec.components.memory.organization import MemoryOrganizationComponent
from parsec.components.organization import (
BaseOrganizationComponent,
OrganizationDump,
TermsOfService,
)
from parsec.components.postgresql.handler import asyncpg_pool_factory
from parsec.components.postgresql.organization import PGOrganizationComponent
from parsec.config import (
BackendConfig,
BaseDatabaseConfig,
LogLevel,
MockedBlockStoreConfig,
MockedEmailConfig,
PostgreSQLDatabaseConfig,
)
from parsec.webhooks import MockedWebhooksComponent
@pydantic.dataclasses.dataclass()
class OrganizationInfo:
id: OrganizationID
created_on: DateTime
is_bootstrapped: bool
bootstrapped_on: DateTime | None
is_expired: bool
expired_on: DateTime | None
active_users_limit: ActiveUsersLimit
user_profile_outsider_allowed: bool
realm_minimum_archiving_period_before_deletion: int
tos: TermsOfService | None
@classmethod
def from_dump(cls, dump: OrganizationDump) -> OrganizationInfo:
return OrganizationInfo(
id=dump.organization_id,
created_on=dump.created_on,
bootstrapped_on=dump.bootstrapped_on,
is_bootstrapped=dump.is_bootstrapped,
expired_on=dump.expired_on,
is_expired=dump.is_expired,
user_profile_outsider_allowed=dump.user_profile_outsider_allowed,
active_users_limit=dump.active_users_limit,
realm_minimum_archiving_period_before_deletion=dump.realm_minimum_archiving_period_before_deletion,
tos=dump.tos,
)
@click.command(name="list-organizations", short_help="List organization present on the server")
@db_server_options
@logging_config_options(default_log_level="INFO")
@asyncio_run
async def cmd(
db: BaseDatabaseConfig,
db_min_connections: int,
db_max_connections: int,
log_level: LogLevel,
log_format: str,
log_file: str | None,
):
backend_config = BackendConfig(
debug=False,
db_config=db,
blockstore_config=MockedBlockStoreConfig(),
email_config=MockedEmailConfig(sender=EmailAddress("tasks@parsec.local")),
server_addr=ParsecAddr("tasks.parsec.local", None, True),
administration_token="",
fake_account_password_algorithm_seed=SecretKey.generate(),
)
async with organization_component_factory(backend_config) as component:
orgs = await list_organizations(component)
adapter = pydantic.TypeAdapter(
dict[
OrganizationID,
OrganizationInfo,
]
)
click.echo_via_pager(adapter.dump_json(orgs, indent=4).decode())
@asynccontextmanager
async def organization_component_factory(
config: BackendConfig,
) -> AsyncGenerator[BaseOrganizationComponent, None]:
if config.db_config.is_mocked():
data = MemoryDatamodel(
{} if config.backend_mocked_data is None else config.backend_mocked_data
)
async with event_bus_factory() as event_bus:
yield MemoryOrganizationComponent(data, event_bus, MockedWebhooksComponent(), config)
else:
assert isinstance(config.db_config, PostgreSQLDatabaseConfig)
async with asyncpg_pool_factory(
url=config.db_config.url,
min_connections=config.db_config.min_connections,
max_connections=config.db_config.max_connections,
) as pool:
yield PGOrganizationComponent(
pool=pool,
webhooks=MockedWebhooksComponent(),
config=None, # pyright: ignore [reportArgumentType]
)
async def list_organizations(
component: BaseOrganizationComponent,
) -> dict[OrganizationID, OrganizationInfo]:
return {
id: OrganizationInfo.from_dump(dump)
for id, dump in (await component.list_organizations()).items()
}