Coverage for polar/benefit/strategies/discord/schemas.py: 94%
34 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 12:42 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 12:42 +0000
1from typing import Literal
3from pydantic import Field, computed_field, field_validator
5from polar.config import settings
6from polar.kit import jwt
7from polar.kit.schemas import Schema
8from polar.models.benefit import BenefitType
10from ..base.schemas import (
11 BenefitBase,
12 BenefitCreateBase,
13 BenefitSubscriberBase,
14 BenefitUpdateBase,
15)
18class BenefitDiscordProperties(Schema):
19 """
20 Properties for a benefit of type `discord`.
21 """
23 guild_id: str = Field(..., description="The ID of the Discord server.")
24 role_id: str = Field(..., description="The ID of the Discord role to grant.")
25 kick_member: bool = Field(
26 ...,
27 description="Whether to kick the member from the Discord server on revocation.",
28 )
30 @computed_field # type: ignore[prop-decorator]
31 @property
32 def guild_token(self) -> str:
33 return jwt.encode(
34 data={"guild_id": self.guild_id},
35 secret=settings.SECRET,
36 type="discord_guild_token",
37 )
40class BenefitDiscordCreateProperties(Schema):
41 """
42 Properties to create a benefit of type `discord`.
43 """
45 guild_token: str = Field(serialization_alias="guild_id")
46 role_id: str = Field(..., description="The ID of the Discord role to grant.")
47 kick_member: bool = Field(
48 ...,
49 description="Whether to kick the member from the Discord server on revocation.",
50 )
52 @field_validator("guild_token")
53 @classmethod
54 def validate_guild_token(cls, v: str) -> str:
55 try:
56 guild_token_data = jwt.decode(
57 token=v, secret=settings.SECRET, type="discord_guild_token"
58 )
59 return guild_token_data["guild_id"]
60 except (KeyError, jwt.DecodeError, jwt.ExpiredSignatureError) as e:
61 raise ValueError(
62 "Invalid token. Please authenticate your Discord server again."
63 ) from e
66class BenefitDiscordSubscriberProperties(Schema):
67 """
68 Properties available to subscribers for a benefit of type `discord`.
69 """
71 guild_id: str = Field(..., description="The ID of the Discord server.")
74class BenefitDiscordCreate(BenefitCreateBase):
75 type: Literal[BenefitType.discord]
76 properties: BenefitDiscordCreateProperties
79class BenefitDiscordUpdate(BenefitUpdateBase):
80 type: Literal[BenefitType.discord]
81 properties: BenefitDiscordCreateProperties | None = None
84class BenefitDiscord(BenefitBase):
85 """
86 A benefit of type `discord`.
88 Use it to automatically invite your backers to a Discord server.
89 """
91 type: Literal[BenefitType.discord]
92 properties: BenefitDiscordProperties
95class BenefitDiscordSubscriber(BenefitSubscriberBase):
96 type: Literal[BenefitType.discord]
97 properties: BenefitDiscordSubscriberProperties