def _getTemplateParams(self, email, recipient): """See `BaseMailer`""" params = super( SourcePackageRecipeBuildMailer, self)._getTemplateParams( email, recipient) params.update({ 'status': self.build.status.title, 'build_id': self.build.id, 'distroseries': self.build.distroseries.name, 'recipe': self.build.recipe.name, 'recipe_owner': self.build.recipe.owner.name, 'archive': self.build.archive.name, 'archive_owner': self.build.archive.owner.name, 'log_url': '', 'component': self.build.current_component.name, 'duration': '', 'builder_url': '', 'build_url': canonical_url(self.build), 'upload_log_url': '', }) if self.build.builder is not None: params['builder_url'] = canonical_url(self.build.builder) if self.build.duration is not None: duration_formatter = DurationFormatterAPI(self.build.duration) params['duration'] = duration_formatter.approximateduration() if self.build.log is not None: params['log_url'] = self.build.log.getURL() if self.build.upload_log is not None: params['upload_log_url'] = self.build.upload_log_url return params
def _getTemplateParams(self, email, recipient): """See `BaseMailer`""" params = super( SourcePackageRecipeBuildMailer, self)._getTemplateParams( email, recipient) params.update({ 'status': self.build.status.title, 'build_id': self.build.id, 'distroseries': self.build.distroseries.name, 'recipe': self.build.recipe.name, 'recipe_owner': self.build.recipe.owner.name, 'archive': self.build.archive.reference, 'log_url': '', 'component': self.build.current_component.name, 'duration': '', 'builder_url': '', 'build_url': canonical_url(self.build), 'upload_log_url': '', }) if self.build.builder is not None: params['builder_url'] = canonical_url(self.build.builder) if self.build.duration is not None: duration_formatter = DurationFormatterAPI(self.build.duration) params['duration'] = duration_formatter.approximateduration() if self.build.log is not None: params['log_url'] = self.build.log_url if self.build.upload_log is not None: params['upload_log_url'] = self.build.upload_log_url return params
def _getTemplateParams(self, email, recipient): """See `BaseMailer`.""" build = self.build params = super(LiveFSBuildMailer, self)._getTemplateParams(email, recipient) params.update({ "archive_tag": build.archive.reference, "build_id": build.id, "build_title": build.title, "livefs_name": build.livefs.name, "version": build.version, "distroseries": build.livefs.distro_series, "architecturetag": build.distro_arch_series.architecturetag, "pocket": build.pocket.name, "build_state": build.status.title, "build_duration": "", "log_url": "", "upload_log_url": "", "builder_url": "", "build_url": canonical_url(self.build), }) if build.duration is not None: duration_formatter = DurationFormatterAPI(build.duration) params["build_duration"] = duration_formatter.approximateduration() if build.log is not None: params["log_url"] = build.log_url if build.upload_log is not None: params["upload_log_url"] = build.upload_log_url if build.builder is not None: params["builder_url"] = canonical_url(build.builder) return params
def describeBacklog(self, estimated_backlog): """Return string describing the current export backlog.""" threshold = timedelta(minutes=10) if estimated_backlog is None or estimated_backlog < threshold: return "" formatter = DurationFormatterAPI(estimated_backlog) time_string = formatter.approximateduration() return "The backlog is approximately %s." % time_string
def _getTemplateParams(self, email, recipient): """See `BaseMailer`.""" build = self.build upload_job = build.last_store_upload_job if upload_job is None: error_message = "" store_url = "" else: error_message = upload_job.error_message or "" store_url = upload_job.store_url or "" params = super(SnapBuildMailer, self)._getTemplateParams(email, recipient) params.update({ "archive_tag": build.archive.reference, "build_id": build.id, "build_title": build.title, "snap_name": build.snap.name, "distroseries": build.snap.distro_series, "architecturetag": build.distro_arch_series.architecturetag, "pocket": build.pocket.name, "build_state": build.status.title, "build_duration": "", "log_url": "", "upload_log_url": "", "builder_url": "", "build_url": canonical_url(build), "snap_authorize_url": canonical_url(build.snap, view_name="+authorize"), "store_error_message": error_message, "store_url": store_url, }) if build.duration is not None: duration_formatter = DurationFormatterAPI(build.duration) params["build_duration"] = duration_formatter.approximateduration() if build.log is not None: params["log_url"] = build.log_url if build.upload_log is not None: params["upload_log_url"] = build.upload_log_url if build.builder is not None: params["builder_url"] = canonical_url(build.builder) return params
def __call__(self): if os.path.exists('+maintenancetime.txt'): message = file('+maintenancetime.txt').read() try: maintenancetime = parseDatetimetz(message) except DateTimeError: # XXX SteveAlexander 2005-09-22: log a warning here. return '' timeleft = maintenancetime - utc_now() if timeleft > self.toomuchtime: return '' elif timeleft < self.notmuchtime: self.timelefttext = 'very very soon' else: self.timelefttext = 'in %s' % ( DurationFormatterAPI(timeleft).approximateduration()) return self.index() return ''
def sendExpirationWarningEmail(self): """See `ITeamMembership`.""" if self.dateexpires is None: raise AssertionError( '%s in team %s has no membership expiration date.' % (self.person.name, self.team.name)) if self.dateexpires < datetime.now(pytz.timezone('UTC')): # The membership has reached expiration. Silently return because # there is nothing to do. The member will have received emails # from previous calls by flag-expired-memberships.py return member = self.person team = self.team if member.is_team: recipient = member.teamowner templatename = 'membership-expiration-warning-bulk.txt' subject = '%s will expire soon from %s' % (member.name, team.name) else: recipient = member templatename = 'membership-expiration-warning-personal.txt' subject = 'Your membership in %s is about to expire' % team.name if team.renewal_policy == TeamMembershipRenewalPolicy.ONDEMAND: how_to_renew = ( "If you want, you can renew this membership at\n" "<%s/+expiringmembership/%s>" % (canonical_url(member), team.name)) elif not self.canChangeExpirationDate(recipient): admins_names = [] admins = team.getDirectAdministrators() assert admins.count() >= 1 if admins.count() == 1: admin = admins[0] how_to_renew = ( "To prevent this membership from expiring, you should " "contact the\nteam's administrator, %s.\n<%s>" % (admin.unique_displayname, canonical_url(admin))) else: for admin in admins: admins_names.append( "%s <%s>" % (admin.unique_displayname, canonical_url(admin))) how_to_renew = ( "To prevent this membership from expiring, you should " "get in touch\nwith one of the team's administrators:\n") how_to_renew += "\n".join(admins_names) else: how_to_renew = ( "To stay a member of this team you should extend your " "membership at\n<%s/+member/%s>" % (canonical_url(team), member.name)) to_addrs = get_contact_email_addresses(recipient) if len(to_addrs) == 0: # The user does not have a preferred email address, he was # probably suspended. return formatter = DurationFormatterAPI( self.dateexpires - datetime.now(pytz.timezone('UTC'))) replacements = { 'recipient_name': recipient.displayname, 'member_name': member.unique_displayname, 'team_url': canonical_url(team), 'how_to_renew': how_to_renew, 'team_name': team.unique_displayname, 'expiration_date': self.dateexpires.strftime('%Y-%m-%d'), 'approximate_duration': formatter.approximateduration()} msg = get_email_template(templatename, app='registry') % replacements from_addr = format_address( team.displayname, config.canonical.noreply_from_address) simple_sendmail(from_addr, to_addrs, subject, msg)
def forExpiringMembership(cls, member, team, dateexpires): """Create a mailer for warning about expiring membership.""" membership = getUtility(ITeamMembershipSet).getByPersonAndTeam( member, team) assert membership is not None if member.is_team: target = member.teamowner template_name = "membership-expiration-warning-bulk.txt" subject = "%s will expire soon from %s" % (member.name, team.name) else: target = member template_name = "membership-expiration-warning-personal.txt" subject = "Your membership in %s is about to expire" % team.name if team.renewal_policy == TeamMembershipRenewalPolicy.ONDEMAND: how_to_renew = ("If you want, you can renew this membership at\n" "<%s/+expiringmembership/%s>" % (canonical_url(member), team.name)) elif not membership.canChangeExpirationDate(target): admins_names = [] admins = team.getDirectAdministrators() assert admins.count() >= 1 if admins.count() == 1: admin = admins[0] how_to_renew = ( "To prevent this membership from expiring, you should " "contact the\nteam's administrator, %s.\n<%s>" % (admin.unique_displayname, canonical_url(admin))) else: for admin in admins: admins_names.append( "%s <%s>" % (admin.unique_displayname, canonical_url(admin))) how_to_renew = ( "To prevent this membership from expiring, you should " "get in touch\nwith one of the team's administrators:\n") how_to_renew += "\n".join(admins_names) else: how_to_renew = ( "To stay a member of this team you should extend your " "membership at\n<%s/+member/%s>" % (canonical_url(team), member.name)) recipients = OrderedDict() for recipient in get_recipients(target): recipients[recipient] = TeamMembershipRecipientReason.forMember( member, team, recipient) formatter = DurationFormatterAPI(dateexpires - datetime.now(pytz.UTC)) extra_params = { "how_to_renew": how_to_renew, "expiration_date": dateexpires.strftime("%Y-%m-%d"), "approximate_duration": formatter.approximateduration(), } from_addr = format_address(team.displayname, config.canonical.noreply_from_address) return cls(subject, template_name, recipients, from_addr, "team-membership-expiration-warning", member, team, membership.proposed_by, membership=membership, extra_params=extra_params, wrap=False, force_wrap=False)
def _assert_mail_is_correct(self, build, notification, recipient, reason, ppa=False): # Assert that the mail sent (which is in notification), matches # the data from the build self.assertEqual(format_address_for_person(recipient), notification['To']) if reason == "buildd-admin": rationale = "Buildd-Admin @launchpad-buildd-admins" expected_for = "launchpad-buildd-admins" else: rationale = reason.title() expected_for = recipient.name self.assertEqual(rationale, notification['X-Launchpad-Message-Rationale']) self.assertEqual(expected_for, notification['X-Launchpad-Message-For']) self.assertEqual('package-build-status', notification['X-Launchpad-Notification-Type']) self.assertEqual('*****@*****.**', notification['X-Creator-Recipient']) self.assertEqual(self.das.architecturetag, notification['X-Launchpad-Build-Arch']) self.assertEqual('main', notification['X-Launchpad-Build-Component']) self.assertEqual(build.status.name, notification['X-Launchpad-Build-State']) self.assertEqual(build.archive.reference, notification['X-Launchpad-Archive']) if ppa and build.archive.distribution.name == 'ubuntu': self.assertEqual(get_ppa_reference(self.ppa), notification['X-Launchpad-PPA']) body = notification.get_payload(decode=True) build_log = 'None' if ppa: source = 'not available' else: source = canonical_url(build.distributionsourcepackagerelease) if build.status == BuildStatus.BUILDING: duration = 'not finished' build_log = 'see builder page' builder = canonical_url(build.builder) elif (build.status == BuildStatus.SUPERSEDED or build.status == BuildStatus.NEEDSBUILD): duration = 'not available' build_log = 'not available' builder = 'not available' elif build.status == BuildStatus.UPLOADING: duration = 'uploading' build_log = 'see builder page' builder = 'not available' else: duration = DurationFormatterAPI( build.duration).approximateduration() builder = canonical_url(build.builder) expected_body = dedent( """ * Source Package: %s * Version: %s * Architecture: %s * Archive: %s * Component: main * State: %s * Duration: %s * Build Log: %s * Builder: %s * Source: %s If you want further information about this situation, feel free to contact us by asking a question on Launchpad (https://answers.launchpad.net/launchpad/+addquestion). %s %s %s """ % (build.source_package_release.sourcepackagename.name, build.source_package_release.version, self.das.architecturetag, build.archive.reference, build.status.title, duration, build_log, builder, source, "-- ", build.title, canonical_url(build))) expected_body += "\n" + REASONS[reason] + "\n" self.assertEqual(expected_body, body)
def _assert_mail_is_correct(self, build, notification, ppa=False): # Assert that the mail sent (which is in notification), matches # the data from the build self.assertEquals('*****@*****.**', notification['X-Creator-Recipient']) self.assertEquals(self.das.architecturetag, notification['X-Launchpad-Build-Arch']) self.assertEquals('main', notification['X-Launchpad-Build-Component']) self.assertEquals(build.status.name, notification['X-Launchpad-Build-State']) if ppa is True: self.assertEquals(get_ppa_reference(self.ppa), notification['X-Launchpad-PPA']) body = notification.get_payload(decode=True) build_log = 'None' if ppa is True: archive = '%s PPA' % get_ppa_reference(build.archive) source = 'not available' else: archive = '%s primary archive' % ( self.distroseries.distribution.name) source = canonical_url(build.distributionsourcepackagerelease) builder = canonical_url(build.builder) if build.status == BuildStatus.BUILDING: duration = 'not finished' build_log = 'see builder page' elif (build.status == BuildStatus.SUPERSEDED or build.status == BuildStatus.NEEDSBUILD): duration = 'not available' build_log = 'not available' builder = 'not available' elif build.status == BuildStatus.UPLOADING: duration = 'uploading' build_log = 'see builder page' builder = 'not available' else: duration = DurationFormatterAPI( build.duration).approximateduration() expected_body = dedent(""" * Source Package: %s * Version: %s * Architecture: %s * Archive: %s * Component: main * State: %s * Duration: %s * Build Log: %s * Builder: %s * Source: %s If you want further information about this situation, feel free to contact a member of the Launchpad Buildd Administrators team. -- %s %s """ % (build.source_package_release.sourcepackagename.name, build.source_package_release.version, self.das.architecturetag, archive, build.status.title, duration, build_log, builder, source, build.title, canonical_url(build))) self.assertEquals(expected_body, body)