@@ -125,6 +125,75 @@ async def send_user_vote(
125
125
126
126
return email_recipient , ""
127
127
128
+ async def start (
129
+ self ,
130
+ email_to : str ,
131
+ project_name : str ,
132
+ version_name : str ,
133
+ selected_revision_number : str ,
134
+ vote_duration_choice : int ,
135
+ subject_data : str ,
136
+ body_data : str ,
137
+ asf_uid : str ,
138
+ asf_fullname : str ,
139
+ release : sql .Release | None = None ,
140
+ promote : bool = True ,
141
+ permitted_recipients : list [str ] | None = None ,
142
+ ) -> sql .Task :
143
+ if release is None :
144
+ release = await self .__data .release (
145
+ project_name = project_name ,
146
+ version = version_name ,
147
+ _project = True ,
148
+ _committee = True ,
149
+ ).demand (storage .AccessError ("Release not found" ))
150
+ if permitted_recipients is None :
151
+ permitted_recipients = util .permitted_voting_recipients (asf_uid , self .__committee_name )
152
+ if email_to not in permitted_recipients :
153
+ # This will be checked again by tasks/vote.py for extra safety
154
+ log .info (f"Invalid mailing list choice: { email_to } not in { permitted_recipients } " )
155
+ raise storage .AccessError ("Invalid mailing list choice" )
156
+
157
+ if promote is True :
158
+ # This verifies the state and sets the phase to RELEASE_CANDIDATE
159
+ error = await interaction .promote_release (
160
+ self .__data , release .name , selected_revision_number , vote_manual = False
161
+ )
162
+ if error :
163
+ raise storage .AccessError (error )
164
+
165
+ # TODO: We also need to store the duration of the vote
166
+ # We can't allow resolution of the vote until the duration has elapsed
167
+ # But we allow the user to specify in the form
168
+ # And yet we also have ReleasePolicy.min_hours
169
+ # Presumably this sets the default, and the form takes precedence?
170
+ # ReleasePolicy.min_hours can also be 0, though
171
+
172
+ # Create a task for vote initiation
173
+ task = sql .Task (
174
+ status = sql .TaskStatus .QUEUED ,
175
+ task_type = sql .TaskType .VOTE_INITIATE ,
176
+ task_args = tasks_vote .Initiate (
177
+ release_name = release .name ,
178
+ email_to = email_to ,
179
+ vote_duration = vote_duration_choice ,
180
+ initiator_id = asf_uid ,
181
+ initiator_fullname = asf_fullname ,
182
+ subject = subject_data ,
183
+ body = body_data ,
184
+ ).model_dump (),
185
+ asf_uid = asf_uid ,
186
+ project_name = project_name ,
187
+ version_name = version_name ,
188
+ )
189
+ self .__data .add (task )
190
+ await self .__data .commit ()
191
+
192
+ # TODO: We should log all outgoing email and the session so that users can confirm
193
+ # And can be warned if there was a failure
194
+ # (The message should be shown on the vote resolution page)
195
+ return task
196
+
128
197
129
198
class CommitteeMember (CommitteeParticipant ):
130
199
def __init__ (
@@ -357,75 +426,6 @@ async def send_resolution(
357
426
await self .__data .commit ()
358
427
return None
359
428
360
- async def start (
361
- self ,
362
- email_to : str ,
363
- project_name : str ,
364
- version_name : str ,
365
- selected_revision_number : str ,
366
- vote_duration_choice : int ,
367
- subject_data : str ,
368
- body_data : str ,
369
- asf_uid : str ,
370
- asf_fullname : str ,
371
- release : sql .Release | None = None ,
372
- promote : bool = True ,
373
- permitted_recipients : list [str ] | None = None ,
374
- ) -> sql .Task :
375
- if release is None :
376
- release = await self .__data .release (
377
- project_name = project_name ,
378
- version = version_name ,
379
- _project = True ,
380
- _committee = True ,
381
- ).demand (storage .AccessError ("Release not found" ))
382
- if permitted_recipients is None :
383
- permitted_recipients = util .permitted_voting_recipients (asf_uid , self .__committee_name )
384
- if email_to not in permitted_recipients :
385
- # This will be checked again by tasks/vote.py for extra safety
386
- log .info (f"Invalid mailing list choice: { email_to } not in { permitted_recipients } " )
387
- raise storage .AccessError ("Invalid mailing list choice" )
388
-
389
- if promote is True :
390
- # This verifies the state and sets the phase to RELEASE_CANDIDATE
391
- error = await interaction .promote_release (
392
- self .__data , release .name , selected_revision_number , vote_manual = False
393
- )
394
- if error :
395
- raise storage .AccessError (error )
396
-
397
- # TODO: We also need to store the duration of the vote
398
- # We can't allow resolution of the vote until the duration has elapsed
399
- # But we allow the user to specify in the form
400
- # And yet we also have ReleasePolicy.min_hours
401
- # Presumably this sets the default, and the form takes precedence?
402
- # ReleasePolicy.min_hours can also be 0, though
403
-
404
- # Create a task for vote initiation
405
- task = sql .Task (
406
- status = sql .TaskStatus .QUEUED ,
407
- task_type = sql .TaskType .VOTE_INITIATE ,
408
- task_args = tasks_vote .Initiate (
409
- release_name = release .name ,
410
- email_to = email_to ,
411
- vote_duration = vote_duration_choice ,
412
- initiator_id = asf_uid ,
413
- initiator_fullname = asf_fullname ,
414
- subject = subject_data ,
415
- body = body_data ,
416
- ).model_dump (),
417
- asf_uid = asf_uid ,
418
- project_name = project_name ,
419
- version_name = version_name ,
420
- )
421
- self .__data .add (task )
422
- await self .__data .commit ()
423
-
424
- # TODO: We should log all outgoing email and the session so that users can confirm
425
- # And can be warned if there was a failure
426
- # (The message should be shown on the vote resolution page)
427
- return task
428
-
429
429
# def __committee_member_or_admin(self, committee: sql.Committee, asf_uid: str) -> None:
430
430
# if not (user.is_committee_member(committee, asf_uid) or user.is_admin(asf_uid)):
431
431
# raise storage.AccessError("You do not have permission to perform this action")
0 commit comments