Coverage for postrfp/mail/schemas.py: 100%

73 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-10-22 21:34 +0000

1from typing import List, Union, Optional, TYPE_CHECKING 

2from datetime import datetime 

3 

4from pydantic import BaseModel, EmailStr, Field, ConfigDict 

5 

6 

7from postrfp import conf 

8 

9if TYPE_CHECKING: 

10 from postrfp.model import User 

11 

12 

13class OrmModel(BaseModel): 

14 model_config = ConfigDict(from_attributes=True) 

15 

16 

17class Org(OrmModel): 

18 id: str 

19 name: str 

20 

21 

22class UserModel(OrmModel): 

23 fullname: str 

24 email: EmailStr 

25 organisation: Org 

26 

27 

28class Proj(OrmModel): 

29 id: int 

30 title: str 

31 status: str = Field( 

32 ..., validation_alias="status_name", serialization_alias="status_name" 

33 ) 

34 owner_organisation: Org = Field(..., alias="owner_org") 

35 author: Optional[UserModel] = None 

36 

37 

38class Issue(OrmModel): 

39 id: int 

40 status: str 

41 deadline: Optional[datetime] = Field(None, alias="deadline_date") 

42 respondent: Optional[Org] = None 

43 respondent_email: Optional[EmailStr] = None 

44 

45 

46class ProjNote(OrmModel): 

47 note_text: str 

48 private: bool 

49 distribution: str = Field(..., alias="pretty_distribution") 

50 author_org: Org = Field(..., alias="organisation") 

51 addressee: Optional[Org] = Field(None, alias="target_organisation") 

52 

53 

54class ScoreSchema(BaseModel): 

55 score_value: Optional[int] = None 

56 comment: Optional[str] = None 

57 question_number: str 

58 respondent_name: str 

59 issue_id: float 

60 

61 

62class EvtSchema(OrmModel): 

63 id: int 

64 timestamp: datetime # output format should be - '%-d %-b %Y %H:%M UTC' 

65 event_type: str 

66 user: Optional[UserModel] = None 

67 organisation: Optional[Org] = None 

68 project: Optional[Proj] = None 

69 issue: Optional[Issue] = None 

70 note: Optional[ProjNote] = None 

71 score: Optional[ScoreSchema] = None 

72 

73 

74class TemplateModelSchema(OrmModel): 

75 system_name: str 

76 host_url_root: str 

77 recipient: Optional[Union[UserModel, EmailStr]] = None 

78 event: EvtSchema 

79 

80 

81class BaseEmail(BaseModel): 

82 To: EmailStr 

83 From: EmailStr 

84 Tag: Optional[str] = None 

85 

86 

87class PostmarkTemplateMessage(BaseEmail): 

88 TemplateModel: TemplateModelSchema 

89 TemplateAlias: str 

90 

91 

92class PostmarkBatchWithTemplates(OrmModel): 

93 Messages: List[PostmarkTemplateMessage] 

94 

95 

96class PostmarkSimpleMessage(BaseEmail): 

97 Subject: str 

98 TextBody: str 

99 

100 

101# Type aliases for cleaner code - use existing Pydantic models 

102TemplateEmailModel = PostmarkTemplateMessage 

103SimpleEmailModel = PostmarkSimpleMessage 

104 

105# Union type for all possible email models 

106EmailModel = Union[PostmarkTemplateMessage, PostmarkSimpleMessage] 

107 

108 

109def build_template_model( 

110 event_model: EvtSchema, recipient_user: "User", to_email: str 

111) -> PostmarkTemplateMessage: 

112 recipient_model: str | UserModel = to_email 

113 if recipient_user: 

114 recipient_model = UserModel.model_validate(recipient_user) 

115 tms = TemplateModelSchema( 

116 system_name=conf.CONF.system_name, 

117 host_url_root=conf.CONF.webapp_hostname, 

118 recipient=recipient_model, 

119 event=event_model, 

120 ) 

121 return PostmarkTemplateMessage( 

122 To=to_email, 

123 From=conf.CONF.email_from_address, 

124 TemplateModel=tms, 

125 TemplateAlias=event_model.event_type, 

126 )