22// for details. All rights reserved. Use of this source code is governed by a
33// BSD-style license that can be found in the LICENSE file.
44
5+ import 'package:pub_dev/frontend/email_sender.dart' ;
6+ import 'package:pub_dev/shared/utils.dart' ;
7+
58import '../../account/agent.dart' ;
69import '../../account/backend.dart' ;
710import '../../package/backend.dart' ;
811import '../../publisher/backend.dart' ;
9- import '../../service/email/backend.dart' ;
10- import '../../shared/datastore.dart' ;
1112import '../../shared/email.dart' ;
1213
1314import '../models.dart' ;
@@ -33,6 +34,7 @@ The list of resolved emails will be deduplicated.
3334 options: {
3435 'to' : 'A comma separated list of email addresses or subjects '
3536 '(the recipients of the messages).' ,
37+ 'cc' : '(optional) same as "to" with addresses that will be CC-d.' ,
3638 'from' : 'The email address to impersonate (`support@pub.dev` by default).' ,
3739 'subject' : 'The subject of the email message.' ,
3840 'body' : 'The text content of the email body.' ,
@@ -61,63 +63,74 @@ The list of resolved emails will be deduplicated.
6163 to != null && to.isNotEmpty,
6264 'to must be given' ,
6365 );
66+ final cc = options['cc' ];
67+ final inReplyTo = options['in-reply-to' ];
68+
69+ final emailList = await _resolveEmails (to! );
70+ final ccEmailList = cc == null ? null : await _resolveEmails (cc);
71+
72+ try {
73+ await emailSender.sendMessage (EmailMessage (
74+ localMessageId: createUuid (),
75+ EmailAddress (from),
76+ emailList.map ((v) => EmailAddress (v)).toList (),
77+ emailSubject! ,
78+ emailBody! ,
79+ ccRecipients:
80+ ccEmailList? .map ((v) => EmailAddress (v)).toList () ?? const [],
81+ inReplyToLocalMessageId: inReplyTo,
82+ ));
83+ return {
84+ 'emails' : emailList,
85+ if (ccEmailList != null ) 'ccEmails' : ccEmailList,
86+ 'sent' : true ,
87+ };
88+ } catch (e, st) {
89+ return {
90+ 'sent' : false ,
91+ 'error' : e.toString (),
92+ 'stackTrace' : st.toString (),
93+ };
94+ }
95+ },
96+ );
6497
65- final emails = < String > {};
66- for (final val in to! .split (',' )) {
67- final value = val.trim ();
68- if (isValidEmail (value)) {
69- emails.add (value);
70- continue ;
71- }
72- final ms = ModerationSubject .tryParse (value);
73- InvalidInputException .check (ms != null , 'Invalid subject: $value ' );
98+ Future <List <String >> _resolveEmails (String value) async {
99+ final emails = < String > {};
100+ for (final val in value.split (',' )) {
101+ final value = val.trim ();
102+ if (isValidEmail (value)) {
103+ emails.add (value);
104+ continue ;
105+ }
106+ final ms = ModerationSubject .tryParse (value);
107+ InvalidInputException .check (ms != null , 'Invalid subject: $value ' );
74108
75- switch (ms! .kind) {
76- case ModerationSubjectKind .package:
77- case ModerationSubjectKind .packageVersion:
78- final pkg = await packageBackend.lookupPackage (ms.package! );
79- if (pkg! .publisherId != null ) {
80- final list =
81- await publisherBackend.getAdminMemberEmails (ms.publisherId! );
82- emails.addAll (list.nonNulls);
83- } else {
84- final list = await accountBackend
85- .lookupUsersById (pkg.uploaders ?? const < String > []);
86- emails.addAll (list.map ((e) => e? .email).nonNulls);
87- }
88- break ;
89- case ModerationSubjectKind .publisher:
109+ switch (ms! .kind) {
110+ case ModerationSubjectKind .package:
111+ case ModerationSubjectKind .packageVersion:
112+ final pkg = await packageBackend.lookupPackage (ms.package! );
113+ if (pkg! .publisherId != null ) {
90114 final list =
91115 await publisherBackend.getAdminMemberEmails (ms.publisherId! );
92116 emails.addAll (list.nonNulls);
93- break ;
94- case ModerationSubjectKind .user:
95- emails.add (ms.email! );
96- break ;
97- default :
98- throw InvalidInputException ('Unknown subject kind: ${ms .kind }' );
99- }
117+ } else {
118+ final list = await accountBackend
119+ .lookupUsersById (pkg.uploaders ?? const < String > []);
120+ emails.addAll (list.map ((e) => e? .email).nonNulls);
121+ }
122+ break ;
123+ case ModerationSubjectKind .publisher:
124+ final list =
125+ await publisherBackend.getAdminMemberEmails (ms.publisherId! );
126+ emails.addAll (list.nonNulls);
127+ break ;
128+ case ModerationSubjectKind .user:
129+ emails.add (ms.email! );
130+ break ;
131+ default :
132+ throw InvalidInputException ('Unknown subject kind: ${ms .kind }' );
100133 }
101-
102- final inReplyTo = options['in-reply-to' ];
103-
104- final emailList = emails.toList ()..sort ();
105- final entity = emailBackend.prepareEntity (EmailMessage (
106- EmailAddress (from),
107- emailList.map ((v) => EmailAddress (v)).toList (),
108- emailSubject! ,
109- emailBody! ,
110- inReplyToLocalMessageId: inReplyTo,
111- ));
112- await withRetryTransaction (dbService, (tx) async {
113- tx.insert (entity);
114- });
115- final sent = await emailBackend.trySendOutgoingEmail (entity);
116-
117- return {
118- 'uuid' : entity.uuid,
119- 'emails' : emailList,
120- 'sent' : sent,
121- };
122- },
123- );
134+ }
135+ return emails.toList ()..sort ();
136+ }
0 commit comments