Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/icalendar/prop/cal_address.py: 54%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

83 statements  

1"""CAL-ADDRESS values from :rfc:`5545`.""" 

2 

3from typing import Any, ClassVar 

4 

5from icalendar.compatibility import Self 

6from icalendar.error import JCalParsingError 

7from icalendar.parser import Parameters 

8from icalendar.parser_tools import DEFAULT_ENCODING, to_unicode 

9 

10 

11class vCalAddress(str): 

12 r"""Calendar User Address 

13 

14 Value Name: 

15 CAL-ADDRESS 

16 

17 Purpose: 

18 This value type is used to identify properties that contain a 

19 calendar user address. 

20 

21 Description: 

22 The value is a URI as defined by [RFC3986] or any other 

23 IANA-registered form for a URI. When used to address an Internet 

24 email transport address for a calendar user, the value MUST be a 

25 mailto URI, as defined by [RFC2368]. 

26 

27 Example: 

28 ``mailto:`` is in front of the address. 

29 

30 .. code-block:: ics 

31 

32 mailto:jane_doe@example.com 

33 

34 Parsing: 

35 

36 .. code-block:: pycon 

37 

38 >>> from icalendar import vCalAddress 

39 >>> cal_address = vCalAddress.from_ical('mailto:jane_doe@example.com') 

40 >>> cal_address 

41 vCalAddress('mailto:jane_doe@example.com') 

42 

43 Encoding: 

44 

45 .. code-block:: pycon 

46 

47 >>> from icalendar import vCalAddress, Event 

48 >>> event = Event() 

49 >>> jane = vCalAddress("mailto:jane_doe@example.com") 

50 >>> jane.name = "Jane" 

51 >>> event["organizer"] = jane 

52 >>> print(event.to_ical().decode().replace('\\r\\n', '\\n').strip()) 

53 BEGIN:VEVENT 

54 ORGANIZER;CN=Jane:mailto:jane_doe@example.com 

55 END:VEVENT 

56 """ 

57 

58 default_value: ClassVar[str] = "CAL-ADDRESS" 

59 params: Parameters 

60 __slots__ = ("params",) 

61 

62 def __new__( 

63 cls, 

64 value: str | bytes, 

65 encoding: str = DEFAULT_ENCODING, 

66 /, 

67 params: dict[str, Any] | None = None, 

68 ) -> Self: 

69 value = to_unicode(value, encoding=encoding) 

70 if "\r" in value or "\n" in value: 

71 raise ValueError( 

72 f"A CAL-ADDRESS value may not contain CR or LF characters: {value!r}" 

73 ) 

74 self = super().__new__(cls, value) 

75 self.params = Parameters(params) 

76 return self 

77 

78 def __repr__(self) -> str: 

79 return f"vCalAddress('{self}')" 

80 

81 def to_ical(self) -> bytes: 

82 return self.encode(DEFAULT_ENCODING) 

83 

84 @classmethod 

85 def from_ical(cls, ical: str | bytes) -> Self: 

86 return cls(ical) 

87 

88 @property 

89 def ical_value(self) -> str: 

90 """The ``mailto:`` part of the address.""" 

91 return str(self) 

92 

93 @property 

94 def email(self) -> str: 

95 """The email address without ``mailto:`` at the start.""" 

96 if self.lower().startswith("mailto:"): 

97 return self[7:] 

98 return str(self) 

99 

100 from icalendar.param import ( 

101 CN, 

102 CUTYPE, 

103 DELEGATED_FROM, 

104 DELEGATED_TO, 

105 DIR, 

106 LANGUAGE, 

107 MEMBER, 

108 PARTSTAT, 

109 ROLE, 

110 RSVP, 

111 SENT_BY, 

112 VALUE, 

113 ) 

114 

115 DELEGATED_FROM = DELEGATED_FROM 

116 """Specify the calendar users that delegated their participation. 

117 

118 This parameter can be specified on properties with a 

119 CAL-ADDRESS value type. This parameter specifies those calendar 

120 users that have delegated their participation in a group-scheduled 

121 event or to-do to the calendar user specified by the property. 

122 The individual calendar address parameter values MUST each be 

123 specified in a quoted-string. 

124 """ 

125 

126 DELEGATED_TO = DELEGATED_TO 

127 """Specify the calendar users to whom participation was delegated. 

128 

129 This parameter can be specified on properties with a 

130 CAL-ADDRESS value type. This parameter specifies those calendar 

131 users to whom participation in a group-scheduled event or to-do was 

132 delegated by the calendar user specified by the property. 

133 The individual calendar address parameter values MUST each be 

134 specified in a quoted-string. 

135 """ 

136 

137 MEMBER = MEMBER 

138 """Specify the group or list membership of a calendar user. 

139 

140 This parameter can be specified on properties with a 

141 CAL-ADDRESS value type. The parameter identifies the groups or 

142 list membership for the calendar user specified by the property. 

143 The parameter value is either a single calendar address in a 

144 quoted-string or a COMMA-separated list of calendar addresses, 

145 each in a quoted-string. The individual calendar address 

146 parameter values MUST each be specified in a quoted-string. 

147 """ 

148 

149 name = CN 

150 

151 @staticmethod 

152 def _get_email(email: str) -> str: 

153 """Extract email and add mailto: prefix if needed. 

154 

155 Handles case-insensitive mailto: prefix checking. 

156 

157 Parameters: 

158 email: Email string that may or may not have mailto: prefix 

159 

160 Returns: 

161 Email string with mailto: prefix 

162 """ 

163 if not email.lower().startswith("mailto:"): 

164 return f"mailto:{email}" 

165 return email 

166 

167 @classmethod 

168 def new( 

169 cls, 

170 email: str, 

171 /, 

172 cn: str | None = None, 

173 cutype: str | None = None, 

174 delegated_from: str | None = None, 

175 delegated_to: str | None = None, 

176 directory: str | None = None, 

177 language: str | None = None, 

178 partstat: str | None = None, 

179 role: str | None = None, 

180 rsvp: bool | None = None, # noqa: FBT001, RUF100 

181 sent_by: str | None = None, 

182 ) -> Self: 

183 """Create a new vCalAddress with RFC 5545 parameters. 

184 

185 Creates a vCalAddress instance with automatic mailto: prefix handling 

186 and support for all standard RFC 5545 parameters. 

187 

188 Parameters: 

189 email: The email address (mailto: prefix added automatically if missing) 

190 cn: Common Name parameter 

191 cutype: Calendar user type (INDIVIDUAL, GROUP, RESOURCE, ROOM) 

192 delegated_from: Email of the calendar user that delegated 

193 delegated_to: Email of the calendar user that was delegated to 

194 directory: Reference to directory information 

195 language: Language for text values 

196 partstat: Participation status (NEEDS-ACTION, ACCEPTED, DECLINED, etc.) 

197 role: Role (REQ-PARTICIPANT, OPT-PARTICIPANT, NON-PARTICIPANT, CHAIR) 

198 rsvp: Whether RSVP is requested 

199 sent_by: Email of the calendar user acting on behalf of this user 

200 

201 Returns: 

202 vCalAddress: A new calendar address with specified parameters 

203 

204 Raises: 

205 TypeError: If email is not a string 

206 

207 Examples: 

208 Basic usage: 

209 

210 >>> from icalendar.prop import vCalAddress 

211 >>> addr = vCalAddress.new("test@test.com") 

212 >>> str(addr) 

213 'mailto:test@test.com' 

214 

215 With parameters: 

216 

217 >>> addr = vCalAddress.new("test@test.com", cn="Test User", role="CHAIR") 

218 >>> addr.params["CN"] 

219 'Test User' 

220 >>> addr.params["ROLE"] 

221 'CHAIR' 

222 """ 

223 if not isinstance(email, str): 

224 raise TypeError(f"Email must be a string, not {type(email).__name__}") 

225 

226 # Handle mailto: prefix (case-insensitive) 

227 email_with_prefix = cls._get_email(email) 

228 

229 # Create the address 

230 addr = cls(email_with_prefix) 

231 

232 # Set parameters if provided 

233 if cn is not None: 

234 addr.params["CN"] = cn 

235 if cutype is not None: 

236 addr.params["CUTYPE"] = cutype 

237 if delegated_from is not None: 

238 addr.params["DELEGATED-FROM"] = cls._get_email(delegated_from) 

239 if delegated_to is not None: 

240 addr.params["DELEGATED-TO"] = cls._get_email(delegated_to) 

241 if directory is not None: 

242 addr.params["DIR"] = directory 

243 if language is not None: 

244 addr.params["LANGUAGE"] = language 

245 if partstat is not None: 

246 addr.params["PARTSTAT"] = partstat 

247 if role is not None: 

248 addr.params["ROLE"] = role 

249 if rsvp is not None: 

250 addr.params["RSVP"] = "TRUE" if rsvp else "FALSE" 

251 if sent_by is not None: 

252 addr.params["SENT-BY"] = cls._get_email(sent_by) 

253 

254 return addr 

255 

256 def to_jcal(self, name: str) -> list: 

257 """Return this property in jCal format.""" 

258 return [name, self.params.to_jcal(), self.VALUE.lower(), self.ical_value] 

259 

260 @classmethod 

261 def examples(cls) -> list[Self]: 

262 """Examples of vCalAddress.""" 

263 return [cls.new("you@example.org", cn="You There")] 

264 

265 @classmethod 

266 def from_jcal(cls, jcal_property: list) -> Self: 

267 """Parse jCal from :rfc:`7265`. 

268 

269 Parameters: 

270 jcal_property: The jCal property to parse. 

271 

272 Raises: 

273 ~error.JCalParsingError: If the provided jCal is invalid. 

274 """ 

275 JCalParsingError.validate_property(jcal_property, cls) 

276 JCalParsingError.validate_value_type(jcal_property[3], str, cls, 3) 

277 return cls( 

278 jcal_property[3], 

279 params=Parameters.from_jcal_property(jcal_property), 

280 ) 

281 

282 

283__all__ = ["vCalAddress"]