Skip to content

Commit 2ff7c4a

Browse files
committed
feat: enhance guild schema detail
1 parent 022cac5 commit 2ff7c4a

File tree

6 files changed

+142
-41
lines changed

6 files changed

+142
-41
lines changed

src/server/domain/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
routes: list[ControllerRouterHandler] = [
2727
system.controllers.system.SystemController,
2828
web.controllers.web.WebController,
29-
guilds.controllers.GuildController,
29+
guilds.controllers.GuildsController,
3030
]
3131
"""Routes for the application."""
3232

src/server/domain/db/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from sqlalchemy.ext.associationproxy import AssociationProxy, association_proxy
99
from sqlalchemy.orm import Mapped, mapped_column, relationship
1010

11-
__all__ = ("GitHubConfig", "Guild", "SOTagsConfig", "User")
11+
__all__ = ("GitHubConfig", "Guild", "SOTagsConfig", "User", "AllowedUsersConfig")
1212

1313

1414
class Guild(UUIDAuditBase):

src/server/domain/guilds/controllers.py

Lines changed: 56 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from litestar.di import Provide
88
from litestar.params import Dependency, Parameter
99

10-
from server.domain.db.models import Guild
1110
from server.domain.guilds import urls
1211
from server.domain.guilds.dependencies import provides_guilds_service
1312
from server.domain.guilds.schemas import GuildSchema, UpdateableGuildSetting
@@ -17,10 +16,10 @@
1716
from advanced_alchemy import FilterTypes
1817
from litestar.pagination import OffsetPagination
1918

20-
__all__ = ("GuildController",)
19+
__all__ = ("GuildsController",)
2120

2221

23-
class GuildController(Controller):
22+
class GuildsController(Controller):
2423
"""Controller for guild-based routes."""
2524

2625
tags = ["Guilds"]
@@ -33,9 +32,9 @@ class GuildController(Controller):
3332
path=urls.GUILD_LIST,
3433
)
3534
async def list_guilds(
36-
self,
37-
guilds_service: GuildsService,
38-
filters: list[FilterTypes] = Dependency(skip_validation=True),
35+
self,
36+
guilds_service: GuildsService,
37+
filters: list[FilterTypes] = Dependency(skip_validation=True),
3938
) -> OffsetPagination[GuildSchema]:
4039
"""List guilds.
4140
@@ -56,16 +55,16 @@ async def list_guilds(
5655
path=urls.GUILD_CREATE,
5756
)
5857
async def create_guild(
59-
self,
60-
guilds_service: GuildsService,
61-
guild_id: int = Parameter(
62-
title="Guild ID",
63-
description="The guild ID.",
64-
),
65-
guild_name: str = Parameter(
66-
title="Guild Name",
67-
description="The guild name.",
68-
),
58+
self,
59+
guilds_service: GuildsService,
60+
guild_id: int = Parameter(
61+
title="Guild ID",
62+
description="The guild ID.",
63+
),
64+
guild_name: str = Parameter(
65+
title="Guild Name",
66+
description="The guild name.",
67+
),
6968
) -> str:
7069
"""Create a guild.
7170
@@ -88,20 +87,20 @@ async def create_guild(
8887
path=urls.GUILD_UPDATE,
8988
)
9089
async def update_guild(
91-
self,
92-
guilds_service: GuildsService,
93-
guild_id: Guild.guild_id = Parameter(
94-
title="Guild ID",
95-
description="The guild ID.",
96-
),
97-
setting: UpdateableGuildSetting = Parameter(
98-
title="Setting",
99-
description="The setting to update.",
100-
),
101-
value: str | int = Parameter(
102-
title="Value",
103-
description="The new value for the setting.",
104-
),
90+
self,
91+
guilds_service: GuildsService,
92+
guild_id: int = Parameter(
93+
title="Guild ID",
94+
description="The guild ID.",
95+
),
96+
setting: UpdateableGuildSetting = Parameter(
97+
title="Setting",
98+
description="The setting to update.",
99+
),
100+
value: str | int = Parameter(
101+
title="Value",
102+
description="The new value for the setting.",
103+
),
105104
) -> str:
106105
"""Update a guild by ID.
107106
@@ -114,5 +113,32 @@ async def update_guild(
114113
Returns:
115114
Guild: Updated guild object
116115
"""
116+
# todo: this is a placeholder, update
117117
await guilds_service.update(guild_id, setting, {"some-config-thing": value})
118118
return f"Guild {guild_id} updated."
119+
120+
@get(
121+
operation_id="GuildDetail",
122+
name="guilds:detail",
123+
summary="Get guild details.",
124+
path=urls.GUILD_DETAIL,
125+
)
126+
async def get_guild(
127+
self,
128+
guilds_service: GuildsService,
129+
guild_id: int = Parameter(
130+
title="Guild ID",
131+
description="The guild ID.",
132+
),
133+
) -> GuildSchema:
134+
"""Get a guild by ID.
135+
136+
Args:
137+
guilds_service (GuildsService): Guilds service
138+
guild_id (int): Guild ID
139+
140+
Returns:
141+
Guild: Guild object
142+
"""
143+
result = await guilds_service.get(guild_id, id_attribute="guild_id")
144+
return guilds_service.to_schema(GuildSchema, result)

src/server/domain/guilds/dependencies.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
from typing import TYPE_CHECKING
55

66
from sqlalchemy import select
7+
from sqlalchemy.orm import joinedload, noload, selectinload
78

8-
from server.domain.db.models import Guild
9+
from server.domain.db.models import AllowedUsersConfig, GitHubConfig, Guild, SOTagsConfig
910
from server.domain.guilds.services import GuildsService
1011
from server.lib import log
1112

@@ -20,15 +21,30 @@
2021

2122

2223
async def provides_guilds_service(db_session: AsyncSession) -> AsyncGenerator[GuildsService, None]:
23-
"""Construct GuildConfig-based repository and service objects for the request.
24+
"""Construct Guilds-based repository and service objects for the request.
2425
2526
Args:
2627
db_session (AsyncSession): SQLAlchemy AsyncSession
2728
2829
Yields:
2930
GuildsService: GuildConfig-based service
3031
"""
31-
async with GuildsService.new(session=db_session, statement=select(Guild).order_by(Guild.guild_id)) as service:
32+
async with GuildsService.new(
33+
session=db_session,
34+
statement=select(Guild)
35+
.order_by(Guild.guild_name)
36+
.options(
37+
selectinload(Guild.github_config).options(
38+
joinedload(GitHubConfig.guild, innerjoin=True).options(noload("*")),
39+
),
40+
selectinload(Guild.sotags_configs).options(
41+
joinedload(SOTagsConfig.guild, innerjoin=True).options(noload("*")),
42+
),
43+
selectinload(Guild.allowed_users).options(
44+
joinedload(AllowedUsersConfig.guild, innerjoin=True).options(noload("*")),
45+
),
46+
),
47+
) as service:
3248
try:
3349
yield service
3450
finally:

src/server/domain/guilds/schemas.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,23 @@
1010
__all__ = ("GuildCreate", "GuildSchema", "GuildUpdate", "UpdateableGuildSetting")
1111

1212

13+
class GitHubConfigSchema(CamelizedBaseModel):
14+
guild_id: UUID
15+
discussion_sync: bool
16+
github_organization: str | None
17+
github_repository: str | None
18+
19+
20+
class SOTagsConfigSchema(CamelizedBaseModel):
21+
guild_id: UUID
22+
tag_name: str
23+
24+
25+
class AllowedUsersConfigSchema(CamelizedBaseModel):
26+
guild_id: int
27+
user_id: UUID
28+
29+
1330
class GuildSchema(CamelizedBaseModel):
1431
"""Schema representing an existing guild."""
1532

@@ -24,6 +41,15 @@ class GuildSchema(CamelizedBaseModel):
2441
issue_linking: bool | None = Field(title="Issue Linking", description="Is issue linking enabled.")
2542
comment_linking: bool | None = Field(title="Comment Linking", description="Is comment linking enabled.")
2643
pep_linking: bool | None = Field(title="PEP Linking", description="Is PEP linking enabled.")
44+
github_config: GitHubConfigSchema | None = Field(
45+
title="GitHub Config", description="The GitHub configuration for the guild."
46+
)
47+
sotags_configs: list[SOTagsConfigSchema] = Field(
48+
title="StackOverflow Tags Configs", description="The StackOverflow tags configuration for the guild."
49+
)
50+
allowed_users: list[AllowedUsersConfigSchema] = Field(
51+
title="Allowed Users", description="The allowed users configuration for the guild."
52+
)
2753

2854

2955
class GuildCreate(CamelizedBaseModel):
@@ -56,9 +82,7 @@ class UpdateableGuildSetting(CamelizedBaseModel):
5682
"""Guild Model Settings"""
5783
prefix: str = Field(title="Prefix", description="The prefix for the guild.")
5884
help_channel_id: int = Field(title="Help Channel ID", description="The channel ID for the help channel.")
59-
sync_label: str = Field(
60-
title="Sync Label", description="The forum label to use for GitHub discussion syncs."
61-
)
85+
sync_label: str = Field(title="Sync Label", description="The forum label to use for GitHub discussion syncs.")
6286
issue_linking: bool = Field(title="Issue Linking", description="Is issue linking enabled.")
6387
comment_linking: bool = Field(title="Comment Linking", description="Is comment linking enabled.")
6488
pep_linking: bool = Field(title="PEP Linking", description="Is PEP linking enabled.")

src/server/domain/guilds/services.py

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@
33

44
from typing import Any
55

6-
from server.domain.db.models import Guild
6+
from server.domain.db.models import AllowedUsersConfig, GitHubConfig, Guild, SOTagsConfig
77
from server.lib import log
8-
from server.lib.repository import SQLAlchemyAsyncSlugRepository
8+
from server.lib.repository import SQLAlchemyAsyncRepository, SQLAlchemyAsyncSlugRepository
99
from server.lib.service import SQLAlchemyAsyncRepositoryService
1010

1111
__all__ = ("GuildsRepository", "GuildsService")
1212

13-
1413
logger = log.get_logger()
1514

1615

@@ -37,3 +36,39 @@ async def to_model(self, data: Guild | dict[str, Any], operation: str | None = N
3736
Project: Converted model
3837
"""
3938
return await super().to_model(data, operation)
39+
40+
41+
class GitHubConfigRepository(SQLAlchemyAsyncRepository[GitHubConfig]):
42+
"""GitHubConfig SQLAlchemy Repository."""
43+
44+
model_type = GitHubConfig
45+
46+
47+
class GitHubConfigService(SQLAlchemyAsyncRepositoryService[GitHubConfig]):
48+
"""Handles basic operations for the guilds' GitHub config."""
49+
50+
repository_type = GitHubConfigRepository
51+
52+
53+
class SOTagsConfigRepository(SQLAlchemyAsyncRepository[SOTagsConfig]):
54+
"""SOTagsConfig SQLAlchemy Repository."""
55+
56+
model_type = SOTagsConfig
57+
58+
59+
class SOTagsConfigService(SQLAlchemyAsyncRepositoryService[SOTagsConfig]):
60+
"""Handles basic operations for the guilds' StackOverflow tags config."""
61+
62+
repository_type = SOTagsConfigRepository
63+
64+
65+
class AllowedUsersConfigRepository(SQLAlchemyAsyncRepository[AllowedUsersConfig]):
66+
"""AllowedUsersConfig SQLAlchemy Repository."""
67+
68+
model_type = AllowedUsersConfig
69+
70+
71+
class AllowedUsersConfigService(SQLAlchemyAsyncRepositoryService[AllowedUsersConfig]):
72+
"""Handles basic operations for the guilds' Allowed Users config."""
73+
74+
repository_type = AllowedUsersConfigRepository

0 commit comments

Comments
 (0)