Coverage for polar/email/schemas.py: 98%

189 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-12-05 16:17 +0000

1import json 1a

2import sys 1a

3from enum import StrEnum 1a

4from typing import Annotated, Literal 1a

5 

6from pydantic import BaseModel, Discriminator, TypeAdapter 1a

7 

8from polar.notifications.notification import ( 1a

9 MaintainerCreateAccountNotificationPayload, 

10 MaintainerNewPaidSubscriptionNotificationPayload, 

11 MaintainerNewProductSaleNotificationPayload, 

12) 

13from polar.order.schemas import OrderBase, OrderItemSchema 1a

14from polar.organization.schemas import Organization 1a

15from polar.product.schemas import BenefitList, ProductBase 1a

16from polar.subscription.schemas import SubscriptionBase 1a

17 

18 

19class EmailTemplate(StrEnum): 1a

20 login_code = "login_code" 1a

21 customer_session_code = "customer_session_code" 1a

22 email_update = "email_update" 1a

23 oauth2_leaked_client = "oauth2_leaked_client" 1a

24 oauth2_leaked_token = "oauth2_leaked_token" 1a

25 order_confirmation = "order_confirmation" 1a

26 organization_access_token_leaked = "organization_access_token_leaked" 1a

27 organization_invite = "organization_invite" 1a

28 organization_account_unlink = "organization_account_unlink" 1a

29 organization_under_review = "organization_under_review" 1a

30 organization_reviewed = "organization_reviewed" 1a

31 personal_access_token_leaked = "personal_access_token_leaked" 1a

32 seat_invitation = "seat_invitation" 1a

33 subscription_cancellation = "subscription_cancellation" 1a

34 subscription_confirmation = "subscription_confirmation" 1a

35 subscription_cycled = "subscription_cycled" 1a

36 subscription_past_due = "subscription_past_due" 1a

37 subscription_revoked = "subscription_revoked" 1a

38 subscription_uncanceled = "subscription_uncanceled" 1a

39 subscription_updated = "subscription_updated" 1a

40 webhook_endpoint_disabled = "webhook_endpoint_disabled" 1a

41 notification_new_sale = "notification_new_sale" 1a

42 notification_new_subscription = "notification_new_subscription" 1a

43 notification_create_account = "notification_create_account" 1a

44 

45 

46class SubscriptionEmail(SubscriptionBase): ... 1a

47 

48 

49class ProductEmail(ProductBase): 1a

50 benefits: BenefitList 1a

51 

52 

53class OrderEmail(OrderBase): 1a

54 description: str 1a

55 items: list[OrderItemSchema] 1a

56 

57 

58class EmailProps(BaseModel): 1a

59 email: str 1a

60 

61 

62class LoginCodeProps(EmailProps): 1a

63 code: str 1a

64 code_lifetime_minutes: int 1a

65 

66 

67class LoginCodeEmail(BaseModel): 1a

68 template: Literal[EmailTemplate.login_code] = EmailTemplate.login_code 1a

69 props: LoginCodeProps 1a

70 

71 

72class CustomerSessionCodeProps(EmailProps): 1a

73 organization: Organization 1a

74 code: str 1a

75 code_lifetime_minutes: int 1a

76 url: str 1a

77 

78 

79class CustomerSessionCodeEmail(BaseModel): 1a

80 template: Literal[EmailTemplate.customer_session_code] = ( 1a

81 EmailTemplate.customer_session_code 

82 ) 

83 props: CustomerSessionCodeProps 1a

84 

85 

86class EmailUpdateProps(EmailProps): 1a

87 token_lifetime_minutes: int 1a

88 url: str 1a

89 

90 

91class EmailUpdateEmail(BaseModel): 1a

92 template: Literal[EmailTemplate.email_update] = EmailTemplate.email_update 1a

93 props: EmailUpdateProps 1a

94 

95 

96class OAuth2LeakedClientProps(EmailProps): 1a

97 token_type: str 1a

98 client_name: str 1a

99 notifier: str 1a

100 url: str 1a

101 

102 

103class OAuth2LeakedClientEmail(BaseModel): 1a

104 template: Literal[EmailTemplate.oauth2_leaked_client] = ( 1a

105 EmailTemplate.oauth2_leaked_client 

106 ) 

107 props: OAuth2LeakedClientProps 1a

108 

109 

110class OAuth2LeakedTokenProps(EmailProps): 1a

111 client_name: str 1a

112 notifier: str 1a

113 url: str 1a

114 

115 

116class OAuth2LeakedTokenEmail(BaseModel): 1a

117 template: Literal[EmailTemplate.oauth2_leaked_token] = ( 1a

118 EmailTemplate.oauth2_leaked_token 

119 ) 

120 props: OAuth2LeakedTokenProps 1a

121 

122 

123class OrderConfirmationProps(EmailProps): 1a

124 organization: Organization 1a

125 product: ProductEmail | None 1a

126 order: OrderEmail 1a

127 url: str 1a

128 

129 

130class OrderConfirmationEmail(BaseModel): 1a

131 template: Literal[EmailTemplate.order_confirmation] = ( 1a

132 EmailTemplate.order_confirmation 

133 ) 

134 props: OrderConfirmationProps 1a

135 

136 

137class OrganizationAccessTokenLeakedProps(EmailProps): 1a

138 organization_access_token: str 1a

139 notifier: str 1a

140 url: str 1a

141 

142 

143class OrganizationAccessTokenLeakedEmail(BaseModel): 1a

144 template: Literal[EmailTemplate.organization_access_token_leaked] = ( 1a

145 EmailTemplate.organization_access_token_leaked 

146 ) 

147 props: OrganizationAccessTokenLeakedProps 1a

148 

149 

150class OrganizationInviteProps(EmailProps): 1a

151 organization_name: str 1a

152 inviter_email: str 1a

153 invite_url: str 1a

154 

155 

156class OrganizationInviteEmail(BaseModel): 1a

157 template: Literal[EmailTemplate.organization_invite] = ( 1a

158 EmailTemplate.organization_invite 

159 ) 

160 props: OrganizationInviteProps 1a

161 

162 

163class OrganizationUnderReviewProps(EmailProps): 1a

164 organization: Organization 1a

165 

166 

167class OrganizationUnderReviewEmail(BaseModel): 1a

168 template: Literal[EmailTemplate.organization_under_review] = ( 1a

169 EmailTemplate.organization_under_review 

170 ) 

171 props: OrganizationUnderReviewProps 1a

172 

173 

174class OrganizationReviewedProps(EmailProps): 1a

175 organization: Organization 1a

176 

177 

178class OrganizationReviewedEmail(BaseModel): 1a

179 template: Literal[EmailTemplate.organization_reviewed] = ( 1a

180 EmailTemplate.organization_reviewed 

181 ) 

182 props: OrganizationReviewedProps 1a

183 

184 

185class PersonalAccessTokenLeakedProps(EmailProps): 1a

186 personal_access_token: str 1a

187 notifier: str 1a

188 url: str 1a

189 

190 

191class PersonalAccessTokenLeakedEmail(BaseModel): 1a

192 template: Literal[EmailTemplate.personal_access_token_leaked] = ( 1a

193 EmailTemplate.personal_access_token_leaked 

194 ) 

195 props: PersonalAccessTokenLeakedProps 1a

196 

197 

198class SeatInvitationProps(EmailProps): 1a

199 organization: Organization 1a

200 product_name: str 1a

201 billing_manager_email: str 1a

202 claim_url: str 1a

203 

204 

205class SeatInvitationEmail(BaseModel): 1a

206 template: Literal[EmailTemplate.seat_invitation] = EmailTemplate.seat_invitation 1a

207 props: SeatInvitationProps 1a

208 

209 

210class SubscriptionPropsBase(EmailProps): 1a

211 organization: Organization 1a

212 product: ProductEmail 1a

213 subscription: SubscriptionEmail 1a

214 url: str 1a

215 

216 

217class SubscriptionCancellationProps(SubscriptionPropsBase): ... 1a

218 

219 

220class SubscriptionCancellationEmail(BaseModel): 1a

221 template: Literal[EmailTemplate.subscription_cancellation] = ( 1a

222 EmailTemplate.subscription_cancellation 

223 ) 

224 props: SubscriptionCancellationProps 1a

225 

226 

227class SubscriptionConfirmationProps(SubscriptionPropsBase): 1a

228 order: OrderEmail 1a

229 

230 

231class SubscriptionConfirmationEmail(BaseModel): 1a

232 template: Literal[EmailTemplate.subscription_confirmation] = ( 1a

233 EmailTemplate.subscription_confirmation 

234 ) 

235 props: SubscriptionConfirmationProps 1a

236 

237 

238class SubscriptionCycledProps(SubscriptionPropsBase): 1a

239 order: OrderEmail 1a

240 

241 

242class SubscriptionCycledEmail(BaseModel): 1a

243 template: Literal[EmailTemplate.subscription_cycled] = ( 1a

244 EmailTemplate.subscription_cycled 

245 ) 

246 props: SubscriptionCycledProps 1a

247 

248 

249class SubscriptionPastDueProps(SubscriptionPropsBase): 1a

250 payment_url: str | None = None 1a

251 

252 

253class SubscriptionPastDueEmail(BaseModel): 1a

254 template: Literal[EmailTemplate.subscription_past_due] = ( 1a

255 EmailTemplate.subscription_past_due 

256 ) 

257 props: SubscriptionPastDueProps 1a

258 

259 

260class SubscriptionRevokedProps(SubscriptionPropsBase): ... 1a

261 

262 

263class SubscriptionRevokedEmail(BaseModel): 1a

264 template: Literal[EmailTemplate.subscription_revoked] = ( 1a

265 EmailTemplate.subscription_revoked 

266 ) 

267 props: SubscriptionRevokedProps 1a

268 

269 

270class SubscriptionUncanceledProps(SubscriptionPropsBase): ... 1a

271 

272 

273class SubscriptionUncanceledEmail(BaseModel): 1a

274 template: Literal[EmailTemplate.subscription_uncanceled] = ( 1a

275 EmailTemplate.subscription_uncanceled 

276 ) 

277 props: SubscriptionUncanceledProps 1a

278 

279 

280class SubscriptionUpdatedProps(SubscriptionPropsBase): 1a

281 order: OrderEmail | None 1a

282 

283 

284class SubscriptionUpdatedEmail(BaseModel): 1a

285 template: Literal[EmailTemplate.subscription_updated] = ( 1a

286 EmailTemplate.subscription_updated 

287 ) 

288 props: SubscriptionUpdatedProps 1a

289 

290 

291class WebhookEndpointDisabledProps(EmailProps): 1a

292 organization: Organization 1a

293 webhook_endpoint_url: str 1a

294 dashboard_url: str 1a

295 

296 

297class WebhookEndpointDisabledEmail(BaseModel): 1a

298 template: Literal[EmailTemplate.webhook_endpoint_disabled] = ( 1a

299 EmailTemplate.webhook_endpoint_disabled 

300 ) 

301 props: WebhookEndpointDisabledProps 1a

302 

303 

304class NotificationNewSaleEmail(BaseModel): 1a

305 template: Literal[EmailTemplate.notification_new_sale] = ( 1a

306 EmailTemplate.notification_new_sale 

307 ) 

308 props: MaintainerNewProductSaleNotificationPayload 1a

309 

310 

311class NotificationNewSubscriptionEmail(BaseModel): 1a

312 template: Literal[EmailTemplate.notification_new_subscription] = ( 1a

313 EmailTemplate.notification_new_subscription 

314 ) 

315 props: MaintainerNewPaidSubscriptionNotificationPayload 1a

316 

317 

318class NotificationCreateAccountEmail(BaseModel): 1a

319 template: Literal[EmailTemplate.notification_create_account] = ( 1a

320 EmailTemplate.notification_create_account 

321 ) 

322 props: MaintainerCreateAccountNotificationPayload 1a

323 

324 

325class OrganizationAccountUnlinkProps(EmailProps): 1a

326 organization_kept_name: str 1a

327 organizations_unlinked: list[str] 1a

328 

329 

330class OrganizationAccountUnlinkEmail(BaseModel): 1a

331 template: Literal[EmailTemplate.organization_account_unlink] = ( 1a

332 EmailTemplate.organization_account_unlink 

333 ) 

334 props: OrganizationAccountUnlinkProps 1a

335 

336 

337Email = Annotated[ 1a

338 LoginCodeEmail 

339 | CustomerSessionCodeEmail 

340 | EmailUpdateEmail 

341 | OAuth2LeakedClientEmail 

342 | OAuth2LeakedTokenEmail 

343 | OrderConfirmationEmail 

344 | OrganizationAccessTokenLeakedEmail 

345 | OrganizationInviteEmail 

346 | OrganizationAccountUnlinkEmail 

347 | OrganizationUnderReviewEmail 

348 | OrganizationReviewedEmail 

349 | PersonalAccessTokenLeakedEmail 

350 | SeatInvitationEmail 

351 | SubscriptionCancellationEmail 

352 | SubscriptionConfirmationEmail 

353 | SubscriptionCycledEmail 

354 | SubscriptionPastDueEmail 

355 | SubscriptionRevokedEmail 

356 | SubscriptionUncanceledEmail 

357 | SubscriptionUpdatedEmail 

358 | WebhookEndpointDisabledEmail 

359 | NotificationNewSaleEmail 

360 | NotificationNewSubscriptionEmail 

361 | NotificationCreateAccountEmail, 

362 Discriminator("template"), 

363] 

364 

365EmailAdapter: TypeAdapter[Email] = TypeAdapter(Email) 1a

366 

367 

368if __name__ == "__main__": 368 ↛ 369line 368 didn't jump to line 369 because the condition on line 368 was never true1a

369 openapi_schema = { 

370 "openapi": "3.1.0", 

371 "paths": {}, 

372 "components": { 

373 "schemas": EmailAdapter.json_schema( 

374 mode="serialization", ref_template="#/components/schemas/{model}" 

375 )["$defs"] 

376 }, 

377 } 

378 sys.stdout.write(json.dumps(openapi_schema, indent=2))