@@ -147,6 +147,76 @@ void main() {
147147 });
148148 });
149149
150+ group ('package uploader invite' , () {
151+ setupTestsWithAdminTokenIssues ((client) => client.adminInvokeAction (
152+ 'package-invite-uploader' ,
153+ AdminInvokeActionArguments (
154+ arguments
: {
'package' : 'oxygen' ,
'email' : '[email protected] ' })));
155+
156+ testWithProfile ('invite + accept' , fn: () async {
157+ final adminClient = createPubApiClient (authToken: siteAdminToken);
158+ final adminOutput = await adminClient.adminInvokeAction (
159+ 'package-invite-uploader' ,
160+ AdminInvokeActionArguments (
161+ arguments
: {
'package' : 'oxygen' ,
'email' : '[email protected] ' }));
162+
163+ expect (adminOutput.output, {
164+ 'message' : 'Invited user' ,
165+ 'package' : 'oxygen' ,
166+ 'emailSent' : true ,
167+ 168+ });
169+
170+ final email = fakeEmailSender.sentMessages.first;
171+ expect (email.subject, 'You have a new invitation to confirm on pub.dev' );
172+
173+ final page = await auditBackend.listRecordsForPackage ('oxygen' );
174+ final r = page.records
175+ .firstWhere ((e) => e.kind == AuditLogRecordKind .uploaderInvited);
176+ expect (r.summary,
177+ '`[email protected] ` invited `[email protected] ` to be an uploader for package `oxygen`.' );
178+
179+ late String consentId;
180+ await withFakeAuthRequestContext (
181+ 182+ () async {
183+ final authenticatedUser = await requireAuthenticatedWebUser ();
184+ final user = authenticatedUser.user;
185+ final consentRow = await dbService.query <Consent >().run ().single;
186+ final consent =
187+ await consentBackend.getConsent (consentRow.consentId, user);
188+ expect (consent.descriptionHtml, contains ('/packages/oxygen' ));
189+ expect (consent.descriptionHtml,
190+ contains ('perform administrative actions' ));
191+ consentId = consentRow.consentId;
192+ },
193+ );
194+
195+ final acceptingClient =
196+ await createFakeAuthPubApiClient (email
: '[email protected] ' );
197+ final rs = await acceptingClient.resolveConsent (
198+ consentId, account_api.ConsentResult (granted: true ));
199+ expect (rs.granted, true );
200+
201+ final page2 = await auditBackend.listRecordsForPackage ('oxygen' );
202+ final r2 = page2.records.firstWhere (
203+ (e) => e.kind == AuditLogRecordKind .uploaderInviteAccepted);
204+ expect (r2.summary,
205+ '`[email protected] ` accepted uploader invite for package `oxygen`.' );
206+
207+ final uploaders =
208+ (await packageBackend.lookupPackage ('oxygen' ))! .uploaders;
209+ expect (uploaders! , hasLength (2 ));
210+ expect (
211+ await Future .wait (uploaders.map ((uploader) async =>
212+ (await accountBackend.lookupUserById (uploader))! .email)),
213+ {
214+ 215+ 216+ });
217+ });
218+ });
219+
150220 group ('create and delete publisher' , () {
151221 testWithProfile ('publisher has packages' , fn: () async {
152222 final p1 = await publisherBackend.lookupPublisher ('example.com' );
0 commit comments